我在 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
我對你發現的內容感到困惑。這已被廣泛記錄。認為它在換行符號處分裂並不是一個流行的誤解。 (不理解它確實分裂是一個普遍的誤解。)
更準確地說,不加引號的變數擴展(如 )$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