我在 FreeBSD 11 上使用 sh (不是 bash/csh),但我不明白这一点:
在控制台中
命令:zpool status -v
结果:
pool: My_pool
state: ONLINE
status: One or more devices is currently being resilvered. The pool will
continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
在脚本中按行分割并一次打印行:
#!/bin/sh
zp="$(zpool status -v)"
for line in $zp; do
echo "$line%"
done
结果:
pool:%
My_pool%
state:%
ONLINE%
status:%
One%
or%
more%
devices%
is%
currently%
being%
resilvered.%
The%
pool%
will%
continue%
to%
function,%
possibly%
in%
a%
degraded%
state.%
action:%
Wait%
根据我能找到的所有信息,我使用的语法对于 sh 来说是正确的,并且应该一次读取一行,而不是一次读取一个单词。
我缺少什么?
答案1
我对你发现的内容感到困惑。你使用的语法对于 sh 和在空格处分割是正确的,而不仅仅是换行符。这已被广泛记录。认为它在换行符处分裂并不是一个流行的误解。 (不理解它确实分裂是一个普遍的误解。)
更准确地说,不加引号的变量扩展(如 )$zp
有时被称为“split+glob”运算符。它的作用是:
- 取变量的值。那是一个字符串。
- 在每个字段分隔符处拆分此值。字段分隔符是变量值中的分隔符
IFS
;默认情况下,该变量包含一个空格、制表符和换行符。 (如果未设置变量,也会使用此默认值。)结果是字符串列表。 - 将列表中的每个元素视为通配符 (glob) 模式。如果它与一个或多个文件名匹配,则该元素将被替换为匹配文件名的列表。否则该元素将被保留。
例如,如果目录包含名为foo
、bar
和 的文件baz
,则以下脚本将打印三行:a*
、bar
和baz
。
zq='a* b*'
for word in $zq; do echo "$word"; done
如果您想在换行符处拆分字符串,则可以通过设置IFS
换行符并禁用通配符扩展来实现。
#!/bin/sh
set -f
IFS='
'
zq=…
for line in $zq; do
…
done
这适用于所有 sh 和 csh 变体。
答案2
要读取行,请使用 shell 的内置命令读功能,
$帮助阅读 |头-2
读取:读取 [-ers] [-u fd] [-t 超时] [-p 提示符] [-a 数组] [-n nchars] [-d delim] [名称 ...]
从标准输入读取一行,如果提供了 -u 选项,则从文件描述符 FD 读取一行
把它放在一个while
循环中,瞧,你有几行:
$ wc -l -w ~/.profile
24 47 /Users/jklowden/.profile
$ for W in $(cat ~/.profile); do echo $W; done | wc -l
47
$ while read L; do echo $L; done < ~/.profile | wc -l
24