遍历行而不是shell脚本的for循环中的单词 [英] Iterate over lines instead of words in a for loop of shell script

查看:239
本文介绍了遍历行而不是shell脚本的for循环中的单词的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是Shell脚本,用于读取框中显示的所有DSF.但是由于该行具有空格,因此将它们显示在不同的行中. 对于那些不了解ioscan -m dsf的人,将其替换为ls -ltr,然后输出是这样,权限和名称显示在不同的行中,但我希望它们在同一行中.

Following is the shell script to read all the DSF present in the box. But since the line is having spaces, it is displaying them in different lines. For those of you who dont understand ioscan -m dsf, replace it by ls -ltr, then the output is such that the permission and names are displayed in different line, but i want them in the same line.

#!/usr/bin/ksh

for a in `ioscan -m dsf`
do
 echo  $a
done

推荐答案

for循环并非旨在循环行".而是循环遍历单词"或字段".

The for loop is not designed to loop over "lines". Instead it loops over "words", or "fields".

惯用的循环行方式是将while循环与read结合使用.

The idiomatic way to loop over lines is to use a while loop in combination with read.

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

请注意,由于管道的原因,while循环位于子外壳中.这可能会引起范围可变的混乱.在bash中,您可以使用进程替换来解决此问题.

Note that the while loop is in a subshell because of the pipe. This can cause some consfusion with variable scope. In bash you can work around this by using process substitution.

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

另请参见 http://mywiki.wooledge.org/BashFAQ/024

for循环使用$IFS(内部字段分隔符)变量中的字符作为分隔符来拆分要循环的值.通常,$IFS包含空格,制表符和换行符.这意味着for循环将在单词"而不是行上循环.

The for loop splits the values to loop over using the characters in the $IFS (Internal field separator) variable as separators. Usually $IFS contains a space, a tab, and a newline. That means the for loop will loop over the "words", not over the lines.

如果您坚持使用for循环遍历行,则必须将$IFS的值更改为仅换行符.但是,如果执行此操作,则必须保存$IFS的旧值并在循环后将其恢复,因为许多其他情况也取决于$IFS.

If you insist on using a for loop to loop over lines you have to change the value of $IFS to only newline. But if you do this you have to save the old value of $IFS and restore that after the loop, because many other things also depend on $IFS.

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

在POSIX shell中,没有 ANSI-C引用($'\n'),您可以这样做:

in POSIX shells, that have no ANSI-C Quoting ($'\n'), you can do it like this:

IFS='
'

即:在引号之间插入实际的新行.

that is: put an actual new line between the quotes.

或者,您可以使用子外壳包含对$IFS的更改:

Alternatively you can use a subshell to contain the change to $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

但是请注意,循环中的命令本身可能取决于$IFS的某些合理设置.然后,您必须在执行命令之前恢复$IFS,并在下一个循环或类似循环之前再次进行设置.我不建议您将$IFS弄乱.太多的命令取决于$IFS中一些合理的值,而对其进行更改将是无尽的错误搜寻的噩梦.

But beware the command in the loop may itself depends on some sane setting for $IFS. Then you have to restore the $IFS before executing the command and set again before the next loop or some such. I do not recommend messing with $IFS. Too many commands depend on some sane values in $IFS and changing it is an endless nightmare of obscure bug hunting.

另请参阅:

  • http://wiki.bash-hackers.org/syntax/ccmd/classic_for
  • http://wiki.bash-hackers.org/commands/builtin/read
  • http://mywiki.wooledge.org/IFS
  • http://mywiki.wooledge.org/SubShell
  • http://mywiki.wooledge.org/ProcessSubstitution

这篇关于遍历行而不是shell脚本的for循环中的单词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆