#!/bin/bash
list="One\ntwo\nthree\nfour"
#Print the list with echo
echo -e "echo: \n$list"
#Set the field separator to new line
IFS=$'\n'
#Try to iterate over each line
echo "For loop:"
for item in $list
do
echo "Item: $item"
done
#Output the variable to a file
echo -e $list > list.txt
#Try to iterate over each line from the cat command
echo "For loop over command output:"
for item in `cat list.txt`
do
echo "Item: $item"
done
这将提供输出:
echo:
One
two
three
four
For loop:
Item: One\ntwo\nthree\nfour
For loop over command output:
Item: One
Item: two
Item: three
Item: four
如您所见,回显变量或遍历
cat
命令正确地逐行打印每一行。但是,第一个for循环将所有项目打印在一行上。有什么想法吗?#1 楼
使用bash,如果要在字符串中嵌入换行符,请使用$''
将字符串括起来:$ list="One\ntwo\nthree\nfour"
$ echo "$list"
One\ntwo\nthree\nfour
$ list=$'One\ntwo\nthree\nfour'
$ echo "$list"
One
two
three
four
如果变量中已有这样的字符串,则可以逐行阅读以下内容:
while IFS= read -r line; do
echo "... $line ..."
done <<< "$list"
评论
请注意,完成<< <<“ $ list”非常重要
–詹森·阿克森(Jason Axelson)
2012-09-26 7:53
之所以<< <<“” $ list“之所以至关重要,是因为它将通过” $ list“作为读取的输入
– Wisbucky
2015年3月11日21:00
我需要强调一下:双重$ list非常关键。
–AndréChalella
2015年6月10日7:44
回声“ $列表” |而...看起来比...做得更清晰<<<“ $ line”
– kyb
18年5月14日在10:07
该方法有缺点,因为while循环将在子shell中运行:循环中分配的任何变量都不会持久。
–格伦·杰克曼
18年5月14日在14:13
#2 楼
您可以使用while
+ read
:some_command | while read line ; do
echo === $line ===
done
顺便说一句。
-e
的echo
选项是非标准的。如果要携带,请改用printf
。评论
请注意,如果使用此语法,则循环内分配的变量不会在循环后停留。奇怪的是,glenn jackman建议的<<<版本确实适用于变量赋值。
– Sparhawk
13-10-3在4:51
@Sparhawk是的,这是因为管道启动了执行while部分的子外壳。 <<<版本没有(至少在新的bash版本中)。
–maxelost
13-10-21在13:53
#3 楼
#!/bin/sh
items="
one two three four
hello world
this should work just fine
"
IFS='
'
count=0
for item in $items
do
count=$((count+1))
echo $count $item
done
评论
这将输出所有项目,而不是行。
– TomaszPosłuszny
15年8月13日在15:05
@TomaszPosłuszny不,这在我的机器上输出3(计数为3)行。注意IFS的设置。您也可以使用IFS = $'\ n'获得相同的效果。
– jmiserez
16年5月10日在12:33
这个和@jmiserez提案都可以很好地工作,谢谢!
– Sebastian B.
20年7月16日在14:34
#4 楼
这是一个有趣的for循环方式:for item in ${list//\n/
}
do
echo "Item: $item"
done
更加明智/可读的是:
cr='
'
for item in ${list//\n/$cr}
do
echo "Item: $item"
done
但是那太复杂了,您只需要在其中留一个空格:
for item in ${list//\n/ }
do
echo "Item: $item"
done
您的
$line
变量不包含换行符。它包含\
的实例,后跟n
。您可以清楚地看到以下内容:$ cat t.sh
#! /bin/bash
list="One\ntwo\nthree\nfour"
echo $list | hexdump -C
$ ./t.sh
00000000 4f 6e 65 5c 6e 74 77 6f 5c 6e 74 68 72 65 65 5c |One\ntwo\nthree\|
00000010 6e 66 6f 75 72 0a |nfour.|
00000016
替换将那些替换为空格,这足以使其在for循环中工作:
$ cat t.sh
#! /bin/bash
list="One\ntwo\nthree\nfour"
echo ${list//\n/ } | hexdump -C
$ ./t.sh
00000000 4f 6e 65 20 74 77 6f 20 74 68 72 65 65 20 66 6f |One two three fo|
00000010 75 72 0a |ur.|
00000013
演示:
$ cat t.sh
#! /bin/bash
list="One\ntwo\nthree\nfour"
echo ${list//\n/ } | hexdump -C
for item in ${list//\n/ } ; do
echo $item
done
$ ./t.sh
00000000 4f 6e 65 20 74 77 6f 20 74 68 72 65 65 20 66 6f |One two three fo|
00000010 75 72 0a |ur.|
00000013
One
two
three
four
评论
有趣的是,您能解释一下这是怎么回事吗?好像您要用新行替换\ n ...原始字符串和新字符串之间有什么区别?
– Alex Spurling
2011年5月16日13:15
@Alex:更新了我的答案-也使用了更简单的版本:-)
–垫子
2011年5月16日13:24
我尝试了一下,如果输入中有空格,它似乎不起作用。在上面的示例中,我们使用“ one \ ntwo \ nthree”,但是如果我们使用“ entry 1 \ entry 2 \ entry 3”,则此操作将失败,因为它还会为该空间添加新行。
– John Rocha
2012年11月8日在18:15
请注意,可以使用$'\ n'代替定义cr。
– devios1
2013年12月21日19:12
这是最正确的答案。即使变量未设置或为空,其他答案也会进入循环。
– Marinos An
20-4-23在10:45
#5 楼
您还可以先将变量转换为数组,然后对其进行迭代。lines="abc
def
ghi"
declare -a theArray
while read -r line
do
theArray+=("$line")
done <<< "$lines"
for line in "${theArray[@]}"
do
echo "$line"
#Do something complex here that would break your read loop
done
仅当您不想弄乱
IFS
并且还具有read
命令可能会发生问题,如果您在循环内调用另一个脚本,则该脚本可能会在返回之前清空读取缓冲区,就像发生在我身上。
评论
只是对所有答案的评论:我必须做$(echo“ $ line” | sed -e's / ^ [[:space:]] * //'),以修剪换行符。