複数の行を返すコマンドがあります。さらに処理するために、それらの行の各単一行を処理する必要があります。
私の現在のコードは、IFS( Internal Field Separator )を変更することで機能します。
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 \"""\").
誰でもこれを手伝ってくれる?ありがとう!
read
ループのwhile
はどうですか?
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"
IFS
を改行のみに設定するだけでは不十分です。 (ところで、なぜバックスペース文字でも分割するのですか?)
コードでは、${ROWS[@]}
(これは$ROWS
を書く奇妙な方法です— — ROWS
は配列ではありません)は二重引用符で囲まれていません。 (二重引用符で囲まれている場合、ROWS
は配列ではないため、単一の文字列を取得します。)したがって、シェルは変数の値を各IFS
文字でフィールドに分割します。次に、各フィールドをグロブパターンとして扱います。たとえば、コマンドによって出力された行の1つに単一文字*
が含まれている場合、これは現在のディレクトリのファイル名に置き換えられます。
set -f
を使用すると、グロビングをオフにできます。シェルのフィールド分割機能を使用するようにIFS
を設定するほとんどの場合、グロビングをオフにする必要もあります。 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."
}
更新の質問で、ヒアドキュメントとヒア文字列の構文を混在させています。
ヒアドキュメントを使用する:
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}")