まず、マイナーだが適用できない答えを切り取ります。呼び出しごとにこれらの式をほとんど使用する必要があるため、find
+xargs
トリックやそのバリアント(find
withなど)は使用できません。-exec
最後にこのトピックに戻ります。
では、より良い例として、次の点を考えてみましょう。
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
パラメータとしてどのように渡しますかprogram
?
これで問題は解決しません
$ ./program $(find -L some/dir -name \*.abc | sort)
program
次のパラメータを取得したため失敗しました。
[0]: ./program
[1]: some/dir/1.abc
[2]: some/dir/2.abc
[3]: some/dir/a
[4]: space.abc
見てわかるように、空白のあるパスは分割され、program
2つの異なるパラメータとして扱われます。
有効日までの見積もり
私のような初心者ユーザーは、これらの問題に直面したときに最終的に動作するまでランダムに引用符を追加する傾向があるようです。ここでは役に立たないようです...
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)"
[0]: ./program
[1]: some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
引用符は単語の区切りを防ぐので、すべてのファイルは単一の引数として渡されます。
別のルート参照
有望なアプローチ:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort)
[1]: "some/dir/1.abc"
[2]: "some/dir/2.abc"
[3]: "some/dir/a
[4]: space.abc"
もちろん引用文もあります。しかし、これ以上説明しない。それらは文字列の一部にすぎません。それで彼らは噴射を止めなかっただけでなく、議論も行いました!
IFSの変更
それから私は遊んでみましたIFS
。とにかく私は「有線経路」自体で問題を引き起こさないようにfind
with-print0
とsort
with -を好みます。それでは、役割分割を強制してすべてを整えるのは-z
どうでしょうか?null
$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z)
[0]: ./program
[1]: some/dir/1.abcsome/dir/2.abcsome/dir/a
[2]: space.abc
したがって、それはまだ空間的に分割されており、垂直に分割されていませんnull
。
私は(上記のように)IFS
beforeとbeforeに課題を入れました。私はwith、with、withoutなどの他の構文も試しました。これらのどれも何の違いもないようです。$(…)
./program
\0
\x0
\x00
'
"
$
今アイデアがなくなりました。もう少し試してみましたが、すべて同じ問題がリストされているようです。
私はまた何ができますか?これは可能ですか?
もちろん、program
受け入れモードを作成して直接検索することもできます。ただし、これを特定の構文に変更するには、多くの二重操作が必要です。 (grep
たとえば、aを介してファイルを提供するのはどうですか?)
program
また、パスのリストを含むファイルを許可することもできます。その後、find
式を一時ファイルに簡単にダンプし、そのファイルへのパスを提供できます。これは、ユーザーが単純なパスのみを持っている場合は、中間ファイルなしで提供できるように直接パスに従うことをサポートできます。ただし、これはビューには適していません。追加の実装が必要なことは言うまでもなく、追加のファイルを生成して処理する必要があります。 (しかし、利点は、引数であるファイルの数がコマンドラインの長さの問題を引き起こし始める場合に役立ちます...)
最後に、私の場合は、find
+(および同様の)トリックが機能しなかったことをもう一度思い出させます。xargs
説明を簡単にするために、1つのパラメータのみを表示します。しかし、私の実際のケースは次のとおりです。
$ ABC_FILES=$(find -L some/dir -name \*.abc | sort)
$ XYZ_FILES=$(find -L other/dir -name \*.xyz | sort)
$ ./program --abc-files $ABC_FILES --xyz-files $XYZ_FILES
だから、1つを検索してももう1つxargs
はどうすればいいのか気になります。
答え1
配列を使用してください。
ファイル名に改行の可能性を処理する必要がない場合は、エスケープできます。
mapfile -t ABC_FILES < <(find -L some/dir -name \*.abc | sort)
mapfile -t XYZ_FILES < <(find -L other/dir -name \*.xyz | sort)
それから
./program --abc-files "${ABC_FILES[@]}" --xyz-files "${XYZ_FILES[@]}"
もしあなたならするファイル名の改行を処理する必要があり、bash> = 4.4の場合は、配列の構成中に名前をnullで終了するためにおよびを-print0
使用できます。-d ''
mapfile -td '' ABC_FILES < <(find -L some/dir -name \*.abc -print0 | sort -z)
(それも似ていますXYZ_FILES
)。もしあなたならいいえ最新のbashを使用すると、nullで終わる読み取りループを使用してファイル名を配列に追加できます。
ABC_FILES=()
while IFS= read -rd '' f; do ABC_FILES+=( "$f" ); done < <(find -L some/dir -name \*.abc -print0 | sort -z)
答え2
IFS = newlineを使用できますが(ファイル名に改行文字が含まれていないと仮定)、置き換える前にシェルでそれを設定する必要があります。
$ ls -1
a file with spaces
able
alpha
baker
boo hoo hoo
bravo
$ # note semicolon here; it's not enough to be in the environment passed
$ # to printf, it must be in the environment OF THE SHELL WHILE PARSING
$ IFS=$'\n'; printf '%s\n' --afiles $(find . -name 'a*') --bfiles $(find . -name 'b*')
--afiles
./able
./a file with spaces
./alpha
--bfiles
./bravo
./boo hoo hoo
./baker
null を使用するzsh
が使用しないこともbash
可能です。改行文字を処理できる$'\0'
としても、bash
一度も使用されていない奇妙な文字がある場合
IFS=$'\1'; ... $(find ... -print0 | tr '\0' '\1') ...
ただし、この方法は@steeldriverの回答に対するコメントで作成した追加の要求、つまりfind aが空の場合、--afilesを省略する追加の要求を処理することはできません。
答え3
なぜあきらめたのか分かりませんxargs
。
だから、1つを検索してももう1つ
xargs
はどうすればいいのか気になります。
文字列は--xyz-files
多くのパラメータの1つにすぎず、プログラムが解釈されるまでそれが特別であると考える理由はありません。どちらの結果xargs
でもfind
これを伝えることができると思います。
{ find -L some/dir -name \*.abc -print0 | sort -z; echo -ne "--xyz-files\0"; find -L other/dir -name \*.xyz -print0 | sort -z; } | xargs -0 ./program --abc-files