私は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つの単語ではなく、一度に1行ずつ読む必要があります。
私は何を見逃していますか?
答え1
私はあなたが何を見つけたのか混乱しています。使用する構文は改行だけでなく、空白のshと分割についても正確です。これは広く文書化されています。改行文字から分割されることは普及した誤解ではありません。 (分割されるという事実を理解していないのは一般的な誤解です。)
より正確に言うと、引用符のない変数拡張(例:)を$zp
「split + glob」演算子と呼ぶこともあります。それがすることは:
- 変数の値を取得します。それは文字列です。
- 各フィールド区切り文字でこの値を分割します。フィールド区切り記号は、デフォルトで
IFS
は変数値の区切り文字です。スペース、タブ、改行。 (このデフォルトは変数が設定されていない場合でも使用されます。)結果は文字列のリストです。 - リストの各要素をワイルドカードパターンとして扱います。 1つ以上のファイル名と一致する場合、この要素は一致するファイル名のリストに置き換えられます。それ以外の場合は要素が保持されます。
たとえば、ディレクトリにfoo
、とというbar
ファイルが含まれている場合、baz
次のスクリプトはa*
、bar
の3行を印刷します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
行を読むには、シェルに組み込まれているコマンドを使用してください。読む機能、
$ヘルプを読む|Head-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