在shell脚本的for循环中迭代行而不是单词

以下是用于读取框中存在的所有DSF的shell脚本。 但是由于该行有空格,所以显示在不同的行中。 对于那些不了解ioscan -m dsf ,用ls -ltrreplace它,然后输出结果是许可和名称显示在不同的行中,但我希望它们在同一行中。

 #!/usr/bin/ksh for a in `ioscan -m dsf` do echo $a done 

for循环不是为循环遍历行而设计的。 for循环遍历“单词”或“字段”。

循环行的惯用方式是结合使用while循环和read

 ioscan -m dsf | while read -r line do printf '%s\n' "$line" done 

请注意,while循环由于管道而位于子外壳中。 在bash中你可以通过使用进程替换来解决这个问题。

 while read -r line do printf '%s\n' "$line" done < <(ioscan -m dsf) 

for循环将使用$IFS (内部字段分隔符)变量中的字符作为分隔符来分隔值。 通常$IFS包含一个空格,一个制表符和一个换行符。 这意味着for循环将遍历“单词”,而不是循环。

如果你坚持使用for循环来遍历行,你必须将$IFS的值更改为只换行。 但是,如果你这样做,你必须保存$IFS的旧值,并在循环后恢复,因为许多其他的东西也依赖于$IFS

 OLDIFS="$IFS" IFS=$'\n' # bash specific for line in $(ioscan -m dsf) do printf '%s\n' "$line" done IFS="$OLDIFS" 

或者,您可以使用subshel​​l来包含对$IFS的更改:

 ( # changes to variables in the subshell stay in the subshell IFS=$'\n' for line in $(ioscan -m dsf) do printf '%s\n' "$line" done ) # $IFS is not changed outside of the subshell 

也可以看看:

用于

for l in $()根据IFS执行分词:

 $ for l in $(printf %b 'ab\nc'); do echo "$l"; done a b c $ IFS=$'\n'; for l in $(printf %b 'ab\nc'); do echo "$l"; done ab c 

如果以后不使用,IFS不必被退回。

for l in $()也执行路径名扩展:

 $ printf %b 'a\n*\n' > file.txt $ IFS=$'\n' $ for l in $(<file.txt); do echo "$l"; done a file.txt $ set -f; for l in $(<file.txt); do echo "$l"; done; set +f a * 

如果IFS=$'\n' ,换行符被剥离和折叠:

 $ printf %b '\n\na\n\nb\n\n' > file.txt $ IFS=$'\n'; for l in $(<file.txt); do echo "$l"; done a b 

$(cat file.txt) (或$(<file.txt) )也读取整个文件到内存。

使用阅读

没有-r反斜杠用于连续行并在其他字符之前移除:

 $ cat file.txt \1\\2\ 3 $ cat file.txt | while read l; do echo "$l"; done 1\23 $ cat file.txt | while read -rl; do echo "$l"; done \1\\2\ 3 

IFS中的字符从行的开头和结尾剥离,但未折叠:

 $ printf %b '1 2 \n\t3\n' | while read -rl; do echo "$l"; done 1 2 3 $ printf %b ' 1 2 \n\t3\n' | while IFS= read -rl; do echo "$l"; done 1 2 3 

如果最后一行不以换行符结尾,则读取赋给它,但在循环的主体之前退出:

 $ printf 'x\ny' | while read l; do echo $l; done x $ printf 'x\ny' | while read l || [[ $l ]]; do echo $l; done x y 

如果一个while循环处于管道中,它也在一个子shell中,所以变量在其外部是不可见的:

 $ x=0; seq 3 | while read l; do let x+=l; done; echo $x 0 $ x=0; while read l; do let x+=l; done < <(seq 3); echo $x 6 $ x=0; x=8 | x=9; echo $x 0