コマンド出力を改行で分割しますか?


9

複数の行を返すコマンドがあります。さらに処理するために、これらの行の各単一行を処理する必要があります。

私の現在のコードはIFS(内部フィールド区切り文字)を変更することで機能します。

ROWS=$(some command returning multiple lines)

O=$IFS #save original IFS
IFS=$(echo -en "\n\b") # set IFS to linebreak

for ROW in ${ROWS[@]}
do
  echo "$ROW"
done

IFS=$O #restore old IFS

IFSを変更せずに、複数行出力の単一行にアクセスするより良い方法はありますか?特に、IFSを変更すると、スクリプトの読みやすさが低下します。

更新:チョロバからのものなど、回答を機能させるのに問題があります。

while IFS= read -r line ; do
    let var+=line #line 42
done << $(sqlite3 -list -nullvalue NULL -separator ',' /var/log/asterisk/master.db "${QUERY}")
echo "$var" # line 44

くれます

./bla.sh: row 44: Warning: here-document at line 43 delimited by end-of-file (wanted `$(sqlite3 -list -nullvalue NULL -separator , /var/log/asterisk/master.db ${QUERY})')
./bla.sh: row 42: let: echo "": syntax error: invalid arithmetic operator. (error causing character is \"""\").

誰でもこれを手伝ってくれる?ありがとう!


チョロバの答えは「する」と言っていますが< <(some command returning multiple lines)、それはあなたがしていることではありません。
ミケル

回答:


13

何についてreadwhileループ?

some command returning multiple lines | while IFS= read -r line ; do
    echo "$line"
done

ただし、パイプはサブシェルで実行されるため、残りのスクリプトの変数値を変更できないことに注意してください。whileループから生き残るために何かが必要な場合は、bashのプロセス置換を使用できます。

while IFS= read -r line ; do
    let var+=line
done < <(some command returning multiple lines)
echo "$var"

プロセス置換を使用することで、このためのスマートなソリューションですbashが、それの価値変数のスコープサブシェルが唯一の問題であることを指摘bashして同じことをやって、zshすべてでこの問題を持っていないでしょう。
カレブ

kshにもこの問題はありません。
Didi Kohen 2012

ありがとう、私はこの解決策を試しましたが、うまくいきません。更新された元の投稿をご覧ください、ありがとう!
stefan.at.wpf 2012

@ stefan.at.wpf:スペースやドル記号を自由に配置することはできません。彼らには意味があります。
チョロバ2012

3

IFS改行のみに設定するだけでは不十分です。(ところで、なぜバックスペース文字でも分割するのですか?)

あなたのコードでは${ROWS[@]}(奇妙な書き方です$ROWSROWS配列ではありません)は二重引用符で囲まれていません。(二重引用符で囲まれている場合ROWSは、配列ではないため、単一の文字列になります。)したがって、シェルは変数の値を各IFS文字のフィールドに分割し、各フィールドをグロブパターンとして扱います。たとえば、コマンドによって出力される行の1つに1文字が含まれている*場合、これは現在のディレクトリのファイル名に置き換えられます。

でグロビングをオフにすることができますset -fIFSシェルのフィールド分割機能を使用するように設定するほとんどの場合、グロビングをオフにする必要もあります。で元に戻しset +fます。

コマンドの出力を1行ずつ読み取るための信頼できるイディオムはwhile IFS= read -rです。

some command returning multiple lines |
while IFS= read -r ROW; do
  
done

ほとんどのシェルは、パイプラインの各コマンドを個別のサブシェルで実行することに注意してください。したがって、変数を設定してループの後で使用する必要がある場合は、これらのコマンドをループと一緒にグループにラップします。(Kshとzshは例外で、親シェルでパイプラインの最後のコマンドを実行します。)

some command returning multiple lines | {
  while IFS= read -r ROW; do
    
    row_count=$((row_count+1))
  done
  echo "There were $row_count rows."
}

1

更新の質問で、ヒアドキュメントとヒア文字列の構文を混在させています。

ヒアドキュメントを使用してください:

while IFS= read -r line ; do
    let var+=line #line 42
done <<ENDMARK
$(sqlite3 -list -nullvalue NULL -separator ',' /var/log/asterisk/master.db "${QUERY}")
ENDMARK

またはここの文字列:

while IFS= read -r line ; do
    let var+=line #line 42
done <<< $(sqlite3 -list -nullvalue NULL -separator ',' /var/log/asterisk/master.db "${QUERY}")
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.