Bash声明性地定义一个循环列表

3
在bash中,我经常制作需要循环遍历我定义的字符串列表的脚本。
例如:
for a in 1 2 3 4; do echo $a; done

然而,我希望在循环之前定义列表(以保持清晰),使其包含空格且没有单独的文件:

例如(但这不会起作用)

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

但您将得到:

list
item
1

我可以使用数组,但我需要为数组中的每个元素编制索引(编辑:请阅读下面的答案,因为您可以将内容附加到数组中。我不知道您可以这样做)。

其他人如何在bash中声明式地定义列表而不使用单独的文件?

抱歉,我忘记提到我想要在for循环逻辑之前在文件顶部定义列表


如果您能具体说明您尝试的方法在哪里出了问题,那将更有帮助。 - unwind
5个回答

4

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

我对这个很熟悉,只是我想在for循环之前定义我的列表。 - Adam Gent
与被接受的答案相反,这种方法在Mac OS X下也适用! - Mischa

3

数组并不难使用:

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

这样做的另一个好处是,如果您需要,每个列表项都可以包含空格。

1
MAPFILE 正确吗?我只是在想 readarray 没有被引用。 - Dr. Jan-Philip Gehrcke
抱歉,我应该事先明确一下。如果你没有为readarray指定数组,那么默认会使用MAPFILEmapfilereadarray命令的另一个名称)。 - chepner
我最喜欢@chepner的答案,因为我想在for循环之前定义列表/数组。我不介意需要更新的bash,因为这只是为了我的个人使用。 - Adam Gent
我已经更新了代码,加入了一个快速替代方案来代替readarray命令,以防你使用的是旧版bash(例如Mac OS X自带的版本)。 - chepner

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

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

为什么需要对数组进行索引?事实上,您可以在不使用索引的情况下向数组追加元素并对其进行迭代。

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

我之前不知道你可以向数组中添加元素 :) - Adam Gent

2

这里有更好的答案,但你也可以使用\n来分隔读取,并在for循环中使用IFS环境变量将变量暂时更改为按换行符而不是空格进行拆分。

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

0

当你可以使用while循环而不是for循环时,你可以利用while read结构和“here document”:

#!/bin/bash

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

参考:如何在Bash中使用“cat << EOF”?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接