UNIXのディレクトリの下に数百のPDFがあります。 PDFの名前は本当に長いです(約60文字)。
次のコマンドを使用してすべてのPDFをまとめて削除しようとしました。
rm -f *.pdf
次のようなエラーが表示されます。
/bin/rm: cannot execute [Argument list too long]
このエラーの解決策は何ですか?このエラーはmv
およびcp
コマンドでも発生しますか?もしそうなら、これらのコマンドを解決する方法?
これが起こる理由は、bashが実際に一致するすべてのファイルにアスタリスクを拡張し、非常に長いコマンドラインを生成するためです。
これを試して:
find . -name "*.pdf" -print0 | xargs -0 rm
警告: これは再帰的な検索であり、サブディレクトリにあるファイルも見つけます(そして削除します)。確認したくない場合にのみ、rmコマンドに-f
を付けてください。
コマンドを非再帰的にするには、次のようにします。
find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm
他の選択肢はfindの-delete
フラグを使うことです:
find . -name "*.pdf" -delete
これは、コマンドライン引数のサイズに関するカーネルの制限です。代わりにfor
ループを使用してください。
これは、execve
およびARG_MAX
定数に関連するシステムの問題です。それについては多くのドキュメントがあります( man execve 、 debian's wiki を参照)。
基本的に、展開はARG_MAX
制限を超えるcommand(およびパラメーター付き)を生成します。カーネル2.6.23
では、制限は128 kB
に設定されていました。この定数は増加しており、次を実行することで値を取得できます。
getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic
for
ループを使用するBashFAQ/095 で推奨されているfor
ループを使用します。RAM/メモリスペース以外には制限はありません。
for f in *.pdf; do rm "$f"; done
また、globはシェル間で強力で一貫した動作を行うため、移植可能なアプローチです( POSIX仕様の一部 )。
注:いくつかのコメントで指摘されているように、これは実際にはより遅くなりますが、より複雑なシナリオに適応できるため、よりメンテナンスしやすくなりますeg1つ以上のアクションを実行したい場合。
find
を使用するあなたが主張する場合、find
を使用できますが、実際にはxargsを使用しないでください」は危険です( NULで区切られていない入力を読み取るとき」:
find . -maxdepth 1 -name '*.pdf' -delete
-maxdepth 1 ... -delete
の代わりに-exec rm {} +
を使用すると、find
が外部プロセスを使用せずに必要なシステムコール自体を実行できるため、高速になります( @ chepner comment のおかげです)。
find
には-delete
アクションがあります。
find . -maxdepth 1 -name '*.pdf' -delete
別の答えは、xargs
にコマンドをまとめて処理させることです。たとえば、ファイル100
を一度にdelete
にするには、ディレクトリにcd
を入力して次のコマンドを実行します。
echo *.pdf | xargs -n 100 rm
またはあなたが試すことができます:
find . -name '*.pdf' -exec rm -f {} \;
非常に多数のファイルを一度に削除しようとしている場合(私は今日485,000以上のディレクトリを削除しました)、おそらくこのエラーに遭遇するでしょう:
/bin/rm: Argument list too long.
問題は、rm -rf *
のように入力すると、*
が、「rm -rfファイル1ファイル2ファイル3ファイル4」のように、一致するすべてのファイルのリストに置き換えられることです。この引数のリストを格納するために割り当てられたメモリの比較的小さいバッファがあり、それがいっぱいになると、シェルはプログラムを実行しません。
この問題を回避するために、多くの人がfindコマンドを使用してすべてのファイルを検索し、それらを1つずつ次のように“ rm”コマンドに渡します。
find . -type f -exec rm -v {} \;
私の問題は、私が50万のファイルを削除する必要があり、それは時間がかかりすぎていたということです。
もっと早くファイルを削除する方法を見つけました。「find」コマンドには「-delete」フラグが組み込まれています。これが私が使用したものです。
find . -type f -delete
この方法では、毎秒約2000ファイルの割合でファイルを削除していました。
削除するときにファイル名を表示することもできます。
find . -type f -print -delete
…あるいは削除するファイルの数を表示してから、削除にかかる時間を計ります。
root@devel# ls -1 | wc -l && time find . -type f -delete
100000
real 0m3.660s
user 0m0.036s
sys 0m0.552s
あなたはこれを試すことができます:
for f in *.pdf
do
rm $f
done
編集:ThiefMasterのコメントは、このような危険なやり方を若いシェルのジェダイには開示しないように私に示唆しているので、私はもっと「より安全な」バージョンを追加する。
echo "# Whooooo" > /tmp/dummy.sh
for f in '*.pdf'
do
echo "rm -i $f" >> /tmp/dummy.sh
done
上記を実行した後、あなたの好みで/tmp/dummy.shファイルを開くだけです。危険なファイル名については一行ごとにチェックし、見つかった場合はコメントアウトしてください。
次に、作業ディレクトリにdummy.shスクリプトをコピーして実行します。
これはセキュリティ上の理由からです。
Bash配列を使うことができます:
files=(*.pdf)
for((I=0;I<${#files[@]};I+=1000)); do
rm -f "${files[@]:I:1000}"
done
このようにして、ステップごとに1000ファイルのバッチで消去されます。
あなたはこのコマンドを使うことができます
find -name "*.pdf" -delete
rm コマンドには、同時に削除できるファイルの制限があります。
ファイルパターンに基づいて rm コマンドベースを複数回使用して削除できる可能性があります。
rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf
find commandから削除することもできます。
find . -name "*.pdf" -exec rm {} \;
スペースや特殊文字を含むファイル名の場合は、次のようにします。
find -maxdepth 1 -name '*.pdf' -exec rm "{}" \;
この文は、現在のディレクトリ(-maxdepth 1)にあるすべてのファイルを拡張子pdf(-name '* .pdf')で検索し、それぞれ削除します(-exec rm "{}")。
式{}はファイルの名前を置き換え、 "{}"はファイル名をスペースや特殊文字を含む文字列として設定します。
find . -type f -name '*xxx' -print -delete
フォームのソースディレクトリをコピー先にコピーしているときに同じ問題に直面していました
ソースディレクトリにファイルがありました
私は cpと-r - オプションを使用
cp -r abc/def/
長すぎる引数リストを警告せずに、すべてのファイルをabcからdefにコピーします。
そしてもう一つ:
cd /path/to/pdf
printf "%s\0" *.[Pp][Dd][Ff] | xargs -0 rm
printf
はShellビルトインであり、私が知る限り、常にそうでした。 printf
がシェルコマンドではない(ただしビルトイン)場合、「argument list too long ...
」致命的エラーの影響を受けません。
したがって、*.[Pp][Dd][Ff]
などのシェルグロビングパターンで安全に使用でき、その出力を削除して(rm
)コマンドをxargs
に渡すことで、十分なファイル名に収まるようにします。シェルコマンドであるrm
コマンドに失敗しないようにコマンドライン。
printf
の\0
は、xargs
コマンドによって処理されるファイル名のヌル区切り文字として機能し、それを区切り文字(-0
)として使用するため、rm
は、ファイル名に空白またはその他の特殊文字が含まれていても失敗しません。
私はこの問題に何度か遭遇した。解決策の多くは、削除する必要がある個々のファイルごとにrm
コマンドを実行します。これは非常に非効率的です。
find . -name "*.pdf" -print0 | xargs -0 rm -rf
ファイル名の最初の4文字に基づいてファイルを削除するためのPythonスクリプトを書きました。
import os
filedir = '/tmp/' #The directory you wish to run rm on
filelist = (os.listdir(filedir)) #gets listing of all files in the specified dir
newlist = [] #Makes a blank list named newlist
for i in filelist:
if str((i)[:4]) not in newlist: #This makes sure that the elements are unique for newlist
newlist.append((i)[:4]) #This takes only the first 4 charcters of the folder/filename and appends it to newlist
for i in newlist:
if 'tmp' in i: #If statment to look for tmp in the filename/dirname
print ('Running command rm -rf '+str(filedir)+str(i)+'* : File Count: '+str(len(os.listdir(filedir)))) #Prints the command to be run and a total file count
os.system('rm -rf '+str(filedir)+str(i)+'*') #Actual Shell command
print ('DONE')
これは私にとってとてもうまくいった。私は約15分でフォルダ内の200万以上の一時ファイルを削除することができました。私は、ほんの少しのコードからtarをコメントアウトしたので、pythonの知識が最小限から全くない人は誰でもこのコードを操作できます。
一時フォルダを作成し、保持したいすべてのファイルとサブフォルダを一時フォルダに移動してから、古いフォルダを削除し、一時フォルダの名前を古いフォルダに変更することができます。
mkdir testit
cd testit
mkdir big_folder tmp_folder
touch big_folder/file1.pdf
touch big_folder/file2.pdf
mv big_folder/file1,pdf tmp_folder/
rm -r big_folder
mv tmp_folder big_folder
rm -r big_folder
は、big_folder
内のすべてのファイルをいくつ削除しても削除します。あなたが最初にあなたが最初にあなたが保持したいすべてのファイル/フォルダーを持っている、この場合それがfile1.pdf
であったことに非常に注意しなければなりません
30/90日を超えて(+)または30/90( - )日を超えて削除したい場合は、以下のexコマンドを使用できます。
例:90日間は90日間のファイル/フォルダの削除後に上記を除外すると、91,92 .... 100日という意味になります。
find <path> -type f -mtime +90 -exec rm -rf {} \;
例:削除したい最新の30日分のファイルについては、以下のコマンドを使用してください( - )
find <path> -type f -mtime -30 -exec rm -rf {} \;
2日以上のファイルをgizしたい場合
find <path> -type f -mtime +2 -exec gzip {} \;
あなたが過去1ヶ月だけからファイル/フォルダーを見たいと思うならば。例:
find <path> -type f -mtime -30 -exec ls -lrt {} \;
30日以上の場合に限り、ファイル/フォルダを一覧表示します。
find <path> -type f -mtime +30 -exec ls -lrt {} \;
find /opt/app/logs -type f -mtime +30 -exec ls -lrt {} \;
すべてのiノードを埋め尽くすアプリケーションによって作成された無駄なログファイルが何百万もあるとき、私は同様の問題に直面しました。私は "locate"に頼って、すべてのファイルをテキストファイルにまとめ、それから一つずつ削除しました。しばらく時間がかかりましたが、仕事をしました!
私はこれを回避する方法を知っているだけです。アイデアはあなたが持っているpdfファイルのリストをファイルにエクスポートすることです。それからそのファイルをいくつかの部分に分割します。それから各部分にリストされているpdfファイルを削除してください。
ls | grep .pdf > list.txt
wc -l list.txt
wc -lは、list.txtに含まれる行数を数えるためのものです。あなたはそれがどれくらいの長さであるかという考えを持っているとき、あなたはそれを半分、四分の一または何かに分割することを決めることができます。 split -lコマンドの使用たとえば、それを600行に分割します。
split -l 600 list.txt
これにより、xaa、xab、xacなどの名前のファイルがいくつか作成されます。これは、分割方法によって異なります。これらのファイルの各リストをコマンドrmに「インポート」するには、これを使用します。
rm $(<xaa)
rm $(<xab)
rm $(<xac)
私の悪い英語ですみません。
私は、ファイルのリストが非常に大きい(> 1e6)場合、これらの答えが遅すぎることを発見しました。これがpythonの並列処理を使った解決策です。私は知っている、私が知っている、これはLinuxではありません...しかしここで他に何もうまくいきませんでした。
(これで時間が節約できました)
# delete files
import os as os
import glob
import multiprocessing as mp
directory = r'your/directory'
os.chdir(directory)
files_names = [i for i in glob.glob('*.{}'.format('pdf'))]
# report errors from pool
def callback_error(result):
print('error', result)
# delete file using system command
def delete_files(file_name):
os.system('rm -rf ' + file_name)
pool = mp.Pool(12)
# or use pool = mp.Pool(mp.cpu_count())
if __== '__main__':
for file_name in files_names:
print(file_name)
pool.apply_async(delete_files,[file_name], error_callback=callback_error)
ディレクトリ内のすべての*.pdf
を削除するには/path/to/dir_with_pdf_files/
mkdir empty_dir # Create temp empty dir
rsync -avh --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/
ワイルドカードを使用してrsync
経由で特定のファイルを削除することは、おそらくあなたが数百万のファイルを持っている場合の最速の解決策です。そしてそれはあなたが得ているエラーの世話をするでしょう。
(オプションのステップ):DRY RUN。削除せずに削除される内容を確認します。 `
rsync -avhn --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/
。 。 。
大量のファイルを削除している間にサーバーやシステムを レスポンシブ に維持する必要がある場合は、各deleteステートメント間のsleep
が良い方法になります。
find . -name "*.pdf" -print0 | while read -d $'\0' file
do
rm "$file"
sleep 0.005 # Sleeps for 5ms, Tweak as needed
done