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
4
  • 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
    Commented Jul 18, 2016 at 7:37
  • @NPS I'm not sure why it isn't working for you - I've added an example to my answer.
    – Tom Fenech
    Commented Jul 18, 2016 at 7:45
  • I found out! I've been messing with IFS and that changes the behaviour. How can I set IFS to its default value?
    – NPS
    Commented Jul 18, 2016 at 8:09
  • 1
    @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.
    – Tom Fenech
    Commented Jul 18, 2016 at 8:13
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
  • 1
    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 _.
    – rici
    Commented Jul 15, 2016 at 17:20
  • 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.
    – NPS
    Commented Jul 18, 2016 at 7:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.