简体   繁体   中英

Bash declaratively defining a list to loop on

In bash I frequently make scripts where I loop over a list of strings that I define.

eg

for a in 1 2 3 4; do echo $a; done

However I would like to define the list (before the loop to keep it clean) so that it contains spaces and with out a separate file:

eg (BUT THIS WILL NOT WORK)

read -r VAR <<HERE
list item 1
list item 2
list item 3
...
HERE

for a in $VAR; do echo $a; done

The expected output above (I would like):

list item 1
list item 2
list item 3
etc...

But you will get:

list
item
1

I could use arrays but I would have to index each element in the array ( EDIT read answers below as you can append to arrays.. I did not know you could ).

How do others declaratively define lists in bash with out using separate files?

Sorry I forgot to mention I want to define the list at the top of the file before the for loop logic

You can use the "HERE Document" like this:

while read a ; do echo "Line: $a" ; done <<HERE
123 ab c
def aldkfgjlaskdjf lkajsdlfkjlasdjf
asl;kdfj ;laksjdf;lkj asd;lf sdpf -aa8
HERE

Arrays aren't so hard to use:

readarray <<HERE
this is my first line
this is my second line
this is my third line
HERE

# Pre bash-4, you would need to build the array more explicity
# Just like readarray defaults to MAPFILE, so read defaults to REPLY
# Tip o' the hat to Dennis Williamson for pointing out that arrays
# are easily appended to.
# while read ; do
#    MAPFILE+=("$REPLY")
# done

for a in "${MAPFILE[@]}"; do
    echo "$a"
done

This has the added benefit of allowing each list item to contain spaces, should you have that need.

while read -r line
do
    var+=$line$'\n'
done <<EOF
foo bar
baz qux
EOF

while read -r line
do
    echo "[$line]"
done <<<"$var"

Why would you need to index arrays? You can append to arrays and iterate over them without using indices.

array+=(value)
for item in "${array[@]}"
do
    something with "$item"
done

There are better answers here, but you can also delimit the read on \\n and temporarily change the variable to split on newlines instead of whitespace in the for loop using the IFS environment variable.

read -d \n -r VAR <<HERE
list item 1
list item 2
list item 3
HERE

IFS_BAK=$IFS
IFS="\n"
for a in $VAR; do echo $a; done
IFS=$IFS_BAK

When it's fine for you to use a while loop instead of a for loop, you can make use of the while read construct and a "here document":

#!/bin/bash

while read LINE; do
    echo "${LINE}"
done << EOF
list item 1
list item 2
list item 3
EOF

ref: How does ` cat << EOF` work in bash?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM