ディレクトリ内のすべてのファイルにアクセスするシェルスクリプトを作成しました/tmp
。ところで 'というエラーメッセージが表示されます
/bin/touch: Argument list too long
。問題の原因は何ですか?
#!/bin/bash
dayNo=1
while test $dayNo -le 200
do
touch `find /tmp/`
sleep 86000
done
答え1
/tmp
ファイルが多すぎます。不適切コマンドラインにすべての名前を一度に表示します(パスにスペースがある場合は、使用しているバージョンも安全ではありません)。
良いニュースは、find
次のように安全かつ正確に実行できることです。
find /tmp -exec touch -c '{}' +
すべてのファイルは以前と同じように検索し、必要なだけ実行してtouch
毎回必要な数のファイルを実行します。
find
-exec
オプション一致するファイルを実行し、パスを置き換えるコマンドを受け入れます{}
。+
つまり、複数のファイルに対して一度に、または各ファイルに対して一度だけコマンドを実行します\;
。touch
コメントで指摘したように、-execdir touch -c '{}' \;
これは厳しく安全ですが、シングルユーザーシステムでは少し遅く、大きな利点はありません。まず、各サブディレクトリに切り替えてから、毎回そのディレクトリのファイルに対してのみコマンドを実行して、特定の競合状態を回避します。この-execdir
オプションは非標準拡張ですが、サポートされています。牛に似た一種の栄養、FreeBSD、オープンBSD、ネットワークBSDとオペレーティングシステム find
s;他の商用 Unices には通常この機能はありません。何を使用しているのかわかりませんが、該当する場合は上記を検討してください。
答え2
シェルは、逆引用符内の式の結果をその行に置き換えます。ただし、システムにはコマンドパラメータリストの長さに制限があります。したがって、/ tmpに何千ものファイルがある場合は、何千もの名前を引数としてコマンドを生成しようとします。これは失敗しました。
これをより簡単に実行できる方法はいくつかあります。検索自体からコマンドを実行できます。ほとんどの最新バージョンでは、分割して各制限を持つ複数のtouch
個別のコマンドを実行できます。
find /tmp -exec touch {} +
答え3
質問のバックティック呼び出しの主な問題は、最初にfindコマンドが/ tmpの下のすべてのファイルを一覧表示し、次にその(巨大な)リストが引数として渡されることです。touch
これは単一の呼び出しには多すぎます。ファイル名にスペース、改行、セミコロン、アンパサンド、パイプ文字などの文字が含まれている場合でも問題が発生する可能性があります。
次の構造を使用する方が良いです。
find /tmp -type f -exec touch -c '{}' +
このfind
コマンドは再帰的に一覧表示されます/tmp
。
-type f
通常のファイルのみを選択するように find に指示する
この-c
オプションを使用すると、touch
Touchが存在しないファイルを生成するのを防ぎます。
例では、いくつかのロジックを省略しているように見えますが、200回だけ実行したい場合は、次のことを試すことができます。
#!/bin/bash 日数= 1 $dayNo -le 200 テスト時 する /tmp -type f -exec touch -c '{}' + 検索 睡眠 86000 日数=$(式1 + ${日数}) 完璧