新しい行とbash変数

新しい行とbash変数

テキストファイル(またはパイプで接続された出力、ここでは重要ではありません)があります。

memcached.uptime 1061374
memcached.curr_connections 480
memcached.cmd_get 478962548
memcached.cmd_set 17641364
memcached.cmd_flush 0

このコマンドを使用すると、cat test.txt | while read i; do echo $i; doneかなり予想される出力が生成されます。

memcached.uptime 1061374
memcached.curr_connections 480
memcached.cmd_get 478962548
etc

ただし、繰り返すとfor i in $(cat test.txt); do echo $i; done他の内容が表示されます。

memcached.uptime
1061374
memcached.curr_connections
480
memcached.cmd_get
478962548
etc

問題は:なぜ? ? ?

答え1

存在する:

cat test.txt | while read i; do echo $i; done

あなたはかなり多くのシェルスクリプティング悪い習慣を落とすことにしました。

まず言及すべきですがシェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?

たとえば、次のように入力します。

-n
/*/*/*/../../../*/*/*
  foo\
bar

シェルループを使用する必要がある場合は、おそらく次のようになります。

{
while IFS= read <&3 -r i; do
  printf '%s\n' "$i" || exit
done
[ -z "$i" ] || printf %s "$i" || exit
} 3< test.txt

存在する

for i in $(cat test.txt); do echo $i; done

これは別の悪い習慣に置き換えることができます。ここに引用しなかった妥当な理由があります$(cat test.txt)。分割+グローブ演算子の分割部分が必要ですが、分割する項目を指定してグローブ部分を無効にすることを忘れました。

IFS='
' # split on newline only. The default value of $IFS
  # contains space, tab and newline which explains why you see
  # one word per line
set -o noglob # disable glob
for i in $(cat test.txt); do
  printf '%s\n' "$i" || exit
done

ループを開始する前に、空白行はまだスキップされ、ファイルの内容を読み取り、メモリに保存します(複数回)。

答え2

答えは、$(command)コマンドの生出力に拡張することです。これにより、シェルはこれに対して一般的な単語分割を実行します。分離には以下が含まれます。どのスペースは単語区切り文字として扱われます。

また、テキストの解析の1つで2つの異なる操作を実行していますreadワイヤーなしで入力言葉$(cat)もう一つはループで出力を繰り返すことですfor。同様の結果を得ることもできますIFS='\n' for i in $(cat test.txt); do echo "$i"; done

関連情報