【问题标题】:Bash declaratively defining a list to loop onBash 以声明方式定义要循环的列表
【发布时间】:2012-05-21 14:35:31
【问题描述】:

在 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

上面的预期输出(我想要):

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

但你会得到:

list
item
1

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

其他人如何在不使用单独文件的情况下以声明方式在 bash 中定义列表?

对不起,我忘了提到我想在 文件顶部在 for 循环逻辑之前定义列表

【问题讨论】:

  • 如果您还指定如何您尝试的方法不起作用会更有帮助。
  • @unwind 我更新了问题。

标签: bash loops


【解决方案1】:

您可以像这样使用“HERE 文档”:

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 循环之前定义我的列表。
  • 与公认的答案相比,这种方法也适用于 Mac OS X!
【解决方案2】:

数组并不难使用:

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

如果您有需要,这还有一个好处是允许每个列表项包含空格。

【讨论】:

  • MAPFILE 正确吗?我只是想知道 readarray 没有被引用。
  • 对不起,我应该说清楚的。如果不为readarray 指定数组,则默认使用MAPFILE。 (mapfilereadarray 命令的另一个名称。)
  • 我最喜欢@chepner 的回答,因为我想在 for 循环之前定义列表/数组。我不介意它需要更新的 bash 作为我自己的用途。
  • 如果您发现自己使用的是旧 bash(例如 Mac OS X 附带的),我已更新为包含 readarray 的快速替换。
【解决方案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

【讨论】:

  • 我不知道你可以追加到数组这就是为什么:)
【解决方案4】:

这里有更好的答案,但您也可以使用IFS 环境变量在for 循环中临时更改变量以在换行符而不是空格处拆分\n

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

【讨论】:

    【解决方案5】:

    如果您可以使用while 循环而不是for 循环,则可以使用while read 构造和“此处文档”:

    #!/bin/bash
    
    while read LINE; do
        echo "${LINE}"
    done << EOF
    list item 1
    list item 2
    list item 3
    EOF
    

    参考:How does ` cat << EOF` work in bash?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-03
      • 1970-01-01
      • 2020-09-26
      • 1970-01-01
      • 2015-08-04
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多