これで問題は解決しません

これで問題は解決しません

まず、マイナーだが適用できない答えを切り取ります。呼び出しごとにこれらの式をほとんど使用する必要があるため、find+xargsトリックやそのバリアント(findwithなど)は使用できません。-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

見てわかるように、空白のあるパスは分割され、program2つの異なるパラメータとして扱われます。

有効日までの見積もり

私のような初心者ユーザーは、これらの問題に直面したときに最終的に動作するまでランダムに引用符を追加する傾向があるようです。ここでは役に立たないようです...

"$(…)"

$ ./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。とにかく私は「有線経路」自体で問題を引き起こさないようにfindwith-print0sortwith -を好みます。それでは、役割分割を強制してすべてを整えるのは-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

私は(上記のように)IFSbeforeと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

関連情報