改行だけでなく、すべてのスペースでテキストを分割して、コマンド出力をシェルの変数として読み込みます。

改行だけでなく、すべてのスペースでテキストを分割して、コマンド出力をシェルの変数として読み込みます。

私は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」演算子と呼ぶこともあります。それがすることは:

  1. 変数の値を取得します。それは文字列です。
  2. 各フィールド区切り文字でこの値を分割します。フィールド区切り記号は、デフォルトでIFSは変数値の区切り文字です。スペース、タブ、改行。 (このデフォルトは変数が設定されていない場合でも使用されます。)結果は文字列のリストです。
  3. リストの各要素をワイルドカードパターンとして扱います。 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

関連情報