从变量中逐行读取shell脚本的内容

15

我有一个多行的脚本变量。 如何遍历这个变量以逐行读取并根据我的需求处理每一行?


在 https://unix.stackexchange.com/questions/9784/how-can-i-read-line-by-line-from-a-variable-in-bash/605491#605491 上有一个类似的问题,我已经在那里写了一个答案。 - Binarus
2个回答

36

考虑以下多行变量:

x=$(echo -e "a\nb\nc d e")

对于每一行,可以采用一个简单的过程:在行前加上前缀=LINE:,并且使用单引号将该行括起来,然后以echo的方式输出即可。以下两行代码均满足此要求:

while read line; do echo "LINE: '${line}'"; done <<< "$x"
或者
while read line; do echo "LINE: '${line}'"; done < <(echo "$x")

两者都不会创建子shell(因此您可以在循环中设置变量并在循环外部访问它们),并且两者都输出结果。

LINE: 'a'
LINE: 'b'
LINE: 'c d e'

但是假设你有以下情况:

x=$(echo -e "a \n b\nc d e")
# note--------^--^

如果你的应用程序(例如解析Git命令输出)需要保留前后空格,那么前导和尾随空白字符可能非常重要。以上两种代码对于变量/数据的输出结果完全相同,这并不是你想要的。为了保留前导和尾随空格,请将 while read line 替换为 while IFS= read -r line 。即以下任一代码。

while IFS= read -r line; do echo "LINE: '${line}'"; done <<< "$x"
或者
while IFS= read -r line; do echo "LINE: '${line}'"; done < <(echo "$x")

会产生

LINE: 'a '
LINE: ' b'
LINE: 'c d e'

详细内容请参考 Greg Wooledge 的精彩 Bash FAQ


这是一个完美的解决方案,只是好奇,为什么不直接使用 x="a\nb\nc d e"? - Senthil Kumar
@SenthilKumar,该字符串包含10个字符:'a','','n','b'等。在双引号内,“\n”不是特殊字符。在bash中,可以编写$"a\nb\nc d e"来嵌入真正的换行符。 "-e"标志告诉echo将"\n"处理为新行,而不是两个单独的字符。 - chepner
1
@chepner:谢谢,$对我来说是新的,但它可以与单引号一起使用$'a\nb\nc d e' - Karoly Horvath
2
@Karoly:我的错误,我使用了错误的引号。双引号用于 gettext 翻译;单引号用于反斜杠扩展。 - chepner
应该提到,这个解决方案之所以有效,是因为echo会添加一个尾随换行符;换句话说,它会改变要解析的变量。这可能或可能不被OP接受。如果没有尾随换行符,read将完全错过最后一行。有关详细信息,请参见https://unix.stackexchange.com/a/9789。 - Binarus

5

尽管我通常使用“while read”处理多行变量,但最近有一个实例,在文件中每行开头的空格被删除了。使用以下代码可以解决这个问题:

printf '%s\n' "$var" | while IFS= read -r line
do
   echo "$line"
done

代码取自Unix Stack Exchange答案

编辑:根据Nicolae Iotu的建议更新,以解决最后一行问题。


1
不错的解决方案,但你需要在printf语句末尾加上一个换行符才能处理最后一行:printf '%s\n' "$var" ... - Nicolae Iotu
好的,谢谢您指出这个问题。我已经根据您的建议更新了我的答案。 - Seth McCauley

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