バックティック(または$(...))展開のスペースを保護する方法はありませんか?
いいえ、ありません。何故ですか?
Bashには、保護すべきものとすべきでないものを知る方法がありません。
UNIXファイル/パイプには配列がありません。これは単なるバイトストリームです。``
または内のコマンド$()
はストリームを出力します。bashはそれを飲み込み、単一の文字列として扱います。そのポイントとして、2つの選択肢しかありません:引用符で囲む、1つの文字列として保持する、または裸にして、bashが構成された動作に従って分割するようにします。
ですから、あなたが配列の配列を持つバイトのフォーマットを定義することである、とすることを望む場合は何をすべきかのようなどのようなツールのxargs
とfind
やる:あなたがそれらを実行する場合-0
、引数、彼らは要素を終了バイナリ配列フォーマットに従って動作しますnullバイト。それ以外の場合は不透明なバイトストリームにセマンティクスを追加します。
残念ながら、bash
nullバイトで文字列を分割するように構成することはできません。/unix//a/110108/17980に感謝しますzsh
。
xargs
コマンドを1回実行し、xargs -0 -n 10000
それで問題が解決したと言いました。そうではなく、10000を超えるパラメーターがある場合に、コマンドが複数回実行されることが保証されます。
厳密に一度だけ実行するか失敗するようにしたい場合は、-x
引数と-n
引数より大きい引数を指定する必要があり-s
ます(実際:長さゼロの引数全体とコマンド名が収まらないほど十分に大きい-s
サイズ)。(man xargs、以下の抜粋を参照)
現在使用しているシステムのスタックは約8Mに制限されているため、ここに制限があります。
$ printf '%s\0' -- {1..1302582} | xargs -x0n 2076858 -s 2076858 /bin/true
xargs: argument list too long
$ printf '%s\0' -- {1..1302581} | xargs -x0n 2076858 -s 2076858 /bin/true
(no output)
バッシュ
外部コマンドを使用したくない場合、/unix//a/110108/17980に示すように、配列を供給するwhile-readループがbashが物事を分割する唯一の方法ですnullバイト。
( . ... "$@" )
スタックサイズの制限を回避するためにスクリプトをソースするというアイデアはクールです(試しましたが、うまくいきました!)が、通常の状況ではおそらく重要ではありません。
プロセスパイプに特別なfdを使用することは、stdinから何かを読みたい場合に重要ですが、それ以外の場合は必要ありません。
それで、日常の家庭のニーズのための最も単純な「ネイティブ」な方法:
files=()
while IFS= read -rd '' file; do
files+=("$file")
done <(find ... -print0)
myscriptornonscript "${files[@]}"
プロセスツリーをきれいで見やすくする必要がある場合は、このメソッドを使用してexec mynonscript "${files[@]}"
、bashプロセスをメモリから削除し、呼び出されたコマンドに置き換えます。xargs
コマンドが一度だけ実行される場合でも、呼び出されたコマンドの実行中は常にメモリに残ります。
ネイティブのbashメソッドに反するのはこれです:
$ time { printf '%s\0' -- {1..1302581} | xargs -x0n 2076858 -s 2076858 /bin/true; }
real 0m2.014s
user 0m2.008s
sys 0m0.172s
$ time {
args=()
while IFS= read -rd '' arg; do
args+=( "$arg" )
done < <(printf '%s\0' -- $(echo {1..1302581}))
/bin/true "${args[@]}"
}
bash: /bin/true: Argument list too long
real 107m51.876s
user 107m38.532s
sys 0m7.940s
bashは配列処理用に最適化されていません。
man xargs:
-n max-args
コマンドラインごとに最大max-args引数を使用します。サイズ(-sオプションを参照)を超えた場合、max-argsよりも少ない引数が使用されます。ただし、-xオプションが指定されていない場合、xargsは終了します。
-s max-chars
コマンドと初期引数、および引数文字列の末尾の終端ヌルを含む、コマンドラインごとに最大max-chars文字を使用します。許容される最大値はシステムに依存し、execの引数の長さの制限として計算され、環境のサイズから2048バイトのヘッドルームを差し引いたものです。この値が128KiBより大きい場合、128Kibがデフォルト値として使用されます。それ以外の場合、デフォルト値は最大値です。1KiBは1024バイトです。
-バツ
サイズ(-sオプションを参照)を超えた場合は終了します。
IFS="
、改行です"
)。しかし、すべてのファイル名でスクリプトを実行する必要はありますか?そうでない場合は、findを使用して各ファイルのスクリプトを実行することを検討してください。