Linuxユーザー向けのアップデート2020:
Linuxを使用している場合のように、最新バージョンのbash(4.4-alpha以上)を使用している場合は、BenjaminW。の回答を使用する必要があります。
Mac OSを使用していて、最後に確認したところ、まだbash 3.2を使用している場合、または古いbashを使用している場合は、次のセクションに進んでください。
bash4.3以前の回答
の出力を配列にfind
取り込むための1つの解決策はbash
次のとおりです。
array=()
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done < <(find . -name "${input}" -print0)
一般に、ファイル名にはスペース、新しい行、その他のスクリプトに反する文字を含めることができるため、これは注意が必要です。find
ファイル名を安全に使用して分離する唯一の方法は-print0
、ヌル文字で区切られたファイル名を出力するを使用することです。bashのreadarray
/mapfile
関数がnullで区切られた文字列をサポートしていれば、これはそれほど不便ではありませんが、サポートしていません。Bashread
はそうしており、それが上記のループにつながります。
[この回答は元々2014年に書かれました。bashの最新バージョンをお持ちの場合は、以下の更新をご覧ください。]
使い方
最初の行は空の配列を作成します: array=()
read
ステートメントが実行されるたびに、nullで区切られたファイル名が標準入力から読み取られます。この-r
オプションはread
、円記号をそのままにしておくように指示します。-d $'\0'
伝えread
入力がNULLで分離されること。に名前を省略しているためread
、シェルは入力をデフォルト名に入れます:REPLY
。
このarray+=("$REPLY")
ステートメントは、新しいファイル名を配列に追加しますarray
。
最後の行は、リダイレクトとコマンド置換を組み合わせてfind
、while
ループの標準入力への出力を提供します。
なぜプロセス置換を使用するのですか?
プロセス置換を使用しなかった場合、ループは次のように記述できます。
array=()
find . -name "${input}" -print0 >tmpfile
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done <tmpfile
rm -f tmpfile
上記では、の出力はfind
一時ファイルに保存され、そのファイルはwhileループへの標準入力として使用されます。プロセス置換の考え方は、そのような一時ファイルを不要にすることです。したがって、while
ループにstdinをから取得させる代わりに、ループにstdinをからtmpfile
取得させることができます<(find . -name ${input} -print0)
。
プロセス置換は広く役立ちます。コマンドがファイルから読み取りたい多くの場所で<(...)
は、ファイル名の代わりにプロセス置換を指定できます。>(...)
コマンドがファイルに書き込みたいファイル名の代わりに使用できる類似の形式があります。
配列と同様に、プロセス置換はbashやその他の高度なシェルの機能です。これはPOSIX標準の一部ではありません。
代替:ラストパイプ
必要に応じて、lastpipe
プロセス置換の代わりに使用できます(ハットヒント:Caesar):
set +m
shopt -s lastpipe
array=()
find . -name "${input}" -print0 | while IFS= read -r -d $'\0'; do array+=("$REPLY"); done; declare -p array
shopt -s lastpipe
現在のシェル(バックグラウンドではない)のパイプラインの最後のコマンドを実行するようにbashに指示します。このようarray
に、パイプラインが完了した後も存在し続けます。lastpipe
ジョブ制御がオフになっている場合にのみ有効になるため、を実行しset +m
ます。(スクリプトでは、コマンドラインとは対照的に、ジョブ制御はデフォルトでオフになっています。)
その他の注意事項
次のコマンドは、シェル配列ではなく、シェル変数を作成します。
array=`find . -name "${input}"`
配列を作成したい場合は、findの出力の周りに親を配置する必要があります。したがって、素朴に、次のことができます。
array=(`find . -name "${input}"`)
問題は、シェルがの結果に対して単語分割を実行するfind
ため、配列の要素が希望どおりであることが保証されないことです。
2019年更新
バージョン4.4-alpha以降、bashは-d
オプションをサポートするようになり、上記のループは不要になりました。代わりに、次のものを使用できます。
mapfile -d $'\0' array < <(find . -name "${input}" -print0)
これに関する詳細については、Benjamin W.の回答を参照(および賛成)してください。