0
myFunction()
{
    > /tmp/file_$1_$2
}

ELEMENTS=("first" "second" "a third" "a fourth")

for elem in "${ELEMENTS[@]}"
do
    myFunction "$elem"
done

I've tried the above code and a bunch of other variants found online:

BASH array with spaces in elements

Loop through array of arrays of string with spaces

https://unix.stackexchange.com/questions/181507/bash-script-array-elements-containing-space-character

But I could never get this to work. What I want my code to do is iterate over these elements:

  1. first
  2. second
  3. a third
  4. a fourth

pass them to myFunction but have the function treat for example a third as 2 arguments, not 1! So I would end up with 4 files:

  1. /tmp/file_first_
  2. /tmp/file_second_
  3. /tmp/file_a_third
  4. /tmp/file_a_fourth

Whatever I try it either treats every word as a different element (6 calls to myFunction) or treats e.g. a third as one argument and creates a file /tmp/file_a third_ or something different yet.

How do I do this right in bash?

2 Answers 2

2

If you want word splitting to occur, then you shouldn't quote your variable:

myFunction $elem

Here's an example, using printf to demonstrate:

$ elements=("first" "second" "a third" "a fourth")
$ func() { printf '/tmp/file_%s_%s\n' "$1" "$2"; }
$ for elem in "${elements[@]}"; do func $elem; done
/tmp/file_first_
/tmp/file_second_
/tmp/file_a_third
/tmp/file_a_fourth
Sign up to request clarification or add additional context in comments.

4 Comments

Finally, I had time to test it and it doesn't seem to work for me. Doesn't split the arguments, with or without the quotes.
@NPS I'm not sure why it isn't working for you - I've added an example to my answer.
I found out! I've been messing with IFS and that changes the behaviour. How can I set IFS to its default value?
@NPS the best thing to do is not to change it in the first place! But if you do, then you can always store the original value in a variable old_IFS=IFS and then restore it later IFS=old_IFS. Alternatively, you can run commands that use a different IFS in a subshell, or if it's just a single command, you can temporarily set the variable using IFS=_ do_something.
2

Only remove double quotes when calling function:

myFunction $elem

The rest of code is ok.

However, you can try it using parameter expansion:

myFunction()
{
    > /tmp/file_${1// /_}
}

ELEMENTS=("first" "second" "a third" "a fourth")

for elem in "${ELEMENTS[@]}"
do
    myFunction "$elem"
done

I think this method can be better because if exists an element like this:

"a fifth ones"

myFunction() will create:

/tmp/file_a_fifth_ones

Explanation:

$ var1="I'm the content of a var"
$ echo "${var1// /_}"

Result:

I'm_the_content_of_a_var

2 Comments

The point about the possibility of more than two words is very good (and I agree), but this solution will not quite produce the same result as OP seems to want when there is only one word, since it won't insert a trailing _.
Your solution is good but I actually do more stuff in my function and I need arguments to be in separate variables. I could, of course, parse the input string and split it manually but that's not how it should be done.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.