1

I want to make an array with string values that have square brackets. but every time I keep getting output unexpected.

selections=()
for i in $choices           
do                       
    selections+=("role[${filenames[$i]}]")
done 

echo ${selections[@]}                                                            

If choices were 1 and 2, and the array filenames[1] and filenames[2] held the values 'A', 'B' I want the selections array to hold the strings role[A], and role[B]

instead the output I get is just roles.

7
  • 3
    This should work. Can you show complete code? Commented Jun 29, 2016 at 19:38
  • 1
    I'm sorry, your claim is not credible. There is no way that your code produces roles as its output. Maybe it produces just role[A]? Else, the output you see is not being produced by the code you present at all. Commented Jun 29, 2016 at 19:57
  • 1
    @JohnBollinger, it is in fact credible. Think of glob expansion. If you have role[abcs] as your result, and roles exists on disk, then you can expand to roles just as you could also expand to rolea or roleb. Commented Jun 29, 2016 at 20:27
  • 1
    @veilig, ...btw, if my theory is accurate, your bug is as confounding as it is due to your failure to quote variable expansions adequately. Run your code through shellcheck.net and fix what it finds. Commented Jun 29, 2016 at 20:29
  • 1
    @CharlesDuffy, not with the inputs the OP describes. Commented Jun 29, 2016 at 20:29

1 Answer 1

2

I can make the code you presented produce the output you wanted, or not, depending on the values I assign to variables filenames and choices.

First, I observe that bash indexed arrays are indexed starting at 0, not 1. If you are using the values 1 and 2 as indices into array filenames, and if that is an indexed array with only two elements, then it may be that ${filenames[2]} expands to nothing. This would be the result if you initialize filenames like so:

# NOT WHAT YOU WANT:
filenames=(A B)

Instead, either assign array elements individually, or add a dummy value at index 0:

# Could work:
filenames=('' A B)

Next, I'm suspicious of choices. Since you're playing with arrays, I speculate that you may have initialized choices as an array, like so:

# NOT CONSISTENT WITH YOUR LATER USAGE:
choices=(1 2)

If you expand an array-valued variable without specifying an index, it is as if you specified index 0. With the above initialization, then, $choices would expand to just 1, not 1 2 as you intend. There are two possibilities: either initialize choices as a flat string:

# Could work:
choices='1 2'

or expand it differently:

# or expand it this way:
for i in "${choices[@]}"

. Do not overlook the quotes, by the way: that particular form will expand to one word per array element, but without the quotes the array elements would be subject to word splitting and other expansions (though that's moot for the particular values you're using in this case).

The quoting applies also, in general, to your echo command: if you do not quote the expansion then you have to analyze the code much more carefully to be confident that it will do what you intend in all cases. It will be subject not only to word splitting, but pathname expansion and a few others. In your case, there is a potential for pathname expansion to be performed, depending on the names of the files in the working directory (thanks @CharlesDuffy). It is far safer to just quote.

Anyway, here is a complete demonstration incorporating your code verbatim and producing the output you want:

#!/bin/bash

filenames=('' 'A' 'B')
choices="1 2"

selections=()
for i in $choices
do
    selections+=("role[${filenames[$i]}]")
done

echo ${selections[@]}

# better:
# echo "${selections[@]}"

Output:

role[A] role[B]

Finally, as I observed in comments, there is no way that your code could output "roles", as you claim it does, given the inputs (variable values) you claim it has. If that's in fact what you see, then either it is not related to the code you presented at all, or your inputs are different than you claim.

Sign up to request clarification or add additional context in comments.

3 Comments

Whether the code you give in your answer produces the output the OP wants depends on the files in the current directory where they run that code. If they have files named roleA or roleB, the output will be the names of those files, not role[A] or role[B]; to fix this, you'd need to fix the quoting.
the quoting around the selections array at the end is what made it work. thanks for your help!
@CharlesDuffy, you are absolutely right, as I edited my answer to say explicitly (but in different words) in anticipation of your comment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.