以下は、出力をmy_command
行配列にグループ化すると思います。
IFS='\n' array_of_lines=$(my_command);
したがって、これは$array_of_lines[1]
出力の最初の行my_command
、$array_of_lines[2]
2番目の行などを参照します。
しかし、上記のコマンドはうまく動作しないようです。私が確認したように、my_command
出力を文字ごとに分割するようです。これは、配列の要素を1行ずつ印刷すると考えられます。私もこれを確認しました:n
print -l $array_of_lines
echo $array_of_lines[1]
echo $array_of_lines[2]
...
2回目の試みで、以下をeval
追加すると役に立つと思いました。
IFS='\n' array_of_lines=$(eval my_command);
しかし、私はそれがないのと同じ結果を得ます。
最後に答えに従ってください。zshで空白を含む要素を一覧表示するIFS
また、zshに入力を分割し、要素を配列に収集する方法を知らせる代わりに、パラメータ拡張フラグを使用してみました。つまり:
array_of_lines=("${(@f)$(my_command)}");
しかし、まだ同じ結果が得られます(分割はで発生しますn
)。
これに関して、次のような質問があります。
Q1.何ですか「正しい」複数行のコマンド出力を収集する方法は?
Q2.IFS
改行だけで分割を指定する方法は?
Q3.上記の3回目のように、パラメータ拡張フラグ(つまり使用)を使用して分割を指定した場合、@f
zshは値を無視しますかIFS
?上記の方法がなぜ機能しないのですか?
答え1
TL、博士:
array_of_lines=("${(@f)$(my_command)}")
最初のエラー(→Q2):2文字にIFS='\n'
設定してください。改行を設定するにはを使用します。IFS
\
n
IFS
IFS=$'\n'
2番目のエラー:変数を配列値に設定するには、要素の周りに括弧が必要ですarray_of_lines=(foo bar)
。
連続したスペースは単一の区切り文字として扱われるため、空行を削除することを除いて機能します。
IFS=$'\n' array_of_lines=($(my_command))
以下では、空白文字を2倍に増やすことで、最後の行を除いて空白行を保持できますIFS
。
IFS=$'\n\n' array_of_lines=($(my_command))
末尾の空行を維持するには、コマンド出力に何かを追加する必要があります。これは、構文解析ではなくコマンド置換自体で発生するためです。
IFS=$'\n\n' array_of_lines=($(my_command; echo .)); unset 'array_of_lines[-1]'
(出力がmy_command
区切られていない行で終わらないと仮定し、終了状態も失われますmy_command
。)
上記のすべてのコードスニペットはデフォルトIFS
以外の値を保持するため、後続のコードを混乱させる可能性があります。ローカル設定を維持するには、IFS
全体をIFS
ローカルを宣言する関数に入れます(ここでコマンドの終了状態も維持されることに注意してください)。
collect_lines() {
local IFS=$'\n\n' ret
array_of_lines=($("$@"; ret=$?; echo .; exit $ret))
ret=$?
unset 'array_of_lines[-1]'
return $ret
}
collect_lines my_command
しかし、私はそれを対処しないことをお勧めしますIFS
。代わりに、f
拡張フラグを使用して改行文字に分割します(→Q1)。
array_of_lines=("${(@f)$(my_command)}")
または、後ろに空行を残します。
array_of_lines=("${(@f)$(my_command; echo .)}")
unset 'array_of_lines[-1]'
そこではの価値はIFS
重要ではありません。テストで分割IFS
印刷コマンドを使用したようです(→Q3)。$array_of_lines
答え2
2つの問題:まず、明らかに二重引用符はバックスラッシュエスケープを説明しません(申し訳ありません:)。$'...'
引用符を使用してください。によるman zshparam
と、単語を配列として収集するには、その単語を括弧で囲む必要があります。だからこれはうまくいきます:
% touch 'a b' c d 'e f'
% IFS=$'\n' arr=($(ls)); print -l $arr
a b
c
d
e f
% print $arr[1]
a b
あなたの質問に答えることはできません3。
答え3
trを使用して改行文字をスペースに置き換えることもできます。
lines=($(mycommand | tr '\n' ' '))
select line in ("${lines[@]}"); do
echo "$line"
break
done