5

Below is my variable declaration and in the shell script, I am looking for a way to loop over the list of strings to get each item.

output='['a.txt', 'b.txt', 'c.txt', 'd.txt']'

I tried the script below but it is not working as expected

for i in "${output}"; do
    echo $i
   
done

Expected result:

a.txt
b.txt
c.txt
d.txt
1
  • You set your variable to the string [a.txt, b.txt, c.txt, d.txt]. First, if you put square brackets into the string, you can't expect the pieces coming out without square bracket, so at best you can expect in the output [a.txt, ...., d.txt]. But this works only if you split the string at the spaces. By using double quotes ("${output}"), you basically ask the shell explicitly to not split the string. Therefore, your loop body is executed only once, with i bound to the complete string. Commented Jun 29, 2022 at 7:23

2 Answers 2

8

In your attempt, quoting the variable forced the shell to regard it as a single value. Failing to quote when you need to is a common beginner error, but quoting when you want the shell to split a value on whitespace (and expand wildcards in the result) is also wrong. Perhaps see also When to wrap quotes around a shell variable?

As long as your items are just tokens, you can save them in a string.

output='a.txt b.txt c.txt d.txt'
for item in $output; do
   echo "$item"  # remember quotes here
done

In isolation, the variable doesn't buy you anything, though.

for item in a.txt b.txt c.txt d.txt
do
    ...

or, if all you want is to print the tokens one by one, simply

printf '%s\n' a.txt b.txt c.txt d.txt

The only data type in sh is a string. There is no simple and safe way to store a sequence of items which require quoting in a variable. (If you can completely control the input, and know what you are doing, try eval; but often, one or both of these conditions are not true.)

As suggested above, if you can avoid saving the values in a variable, you can use any quoting you like!

for item in "an item" another \
    'yet one more (with "nested quotes" even, see?)'
do
    echo "$item"  # now the quotes are important!
done

Bash and Ksh etc have arrays, so you can do things like

items=("an item" another 'yet one more (with "nested quotes" even, see?)')
printf '%s\n' "${items[@]}"

but this is not available in plain sh.

(For what it's worth, you also cannot nest quotes the way you tried to.

input='['a.txt', '

creates a string consisting of (quoted) [ immediately adjacent to (unquoted) a.txt imrediately adjacent to (quoted) comma and space. The shell will simply join together the adjacent strings into a single string after quote removal.)

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

2 Comments

Regarding the quote in the two echo "$item" lines, is there another reason for their presence beside preventing wildcard expansion ?
Quotes prevent whitespace tokenization and wildcard expansion. For echo in particular, whitespace tokenization is not important, but the general rule should be to always quote uniess you want to force whitespace tokenization and wildcard expansion. See also When to wrap quotes around a shell variable
0

From the documentation of GNU Bash,

"A list is a sequence of one or more pipelines separated by one of the operators ‘;’, ‘&’, ‘&&’, or ‘||’, and optionally terminated by one of ‘;’, ‘&’, or a newline."

Also, you need to remember Bash supports one-dimensional numerically indexed and associative array types, unfortunately, as per my knowledge bash doesn't support a "List" type data structure.

And for that reason you need to modify your variable declaration like the below:

output=("a.txt" "b.txt" "c.txt" "d.txt")

1 Comment

There is no indication that the OP asks about a Bash solution; the question is conspicuously only tagged sh. If they were to adopt your solution, they would also have to use array syntax to loop over the values.

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.