3

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
user1934428
  • 19,864
  • 7
  • 42
  • 87
user3156326
  • 81
  • 2
  • 7
  • 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. – user1934428 Jun 29 '22 at 07:23

2 Answers2

5

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.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Regarding the quote in the two `echo "$item"` lines, is there another reason for their presence beside preventing wildcard expansion ? – 3r1d Apr 12 '23 at 11:06
  • 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](https://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-shell-variable) – tripleee Apr 12 '23 at 11:24
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")
Papai from BEKOAIL
  • 1,469
  • 1
  • 11
  • 17
  • There is no indication that the OP asks about a Bash solution; the question is conspicuously only tagged [tag:sh]. If they were to adopt your solution, they would also have to use array syntax to loop over the values. – tripleee Jun 29 '22 at 13:25