rm、cp、mvコマンドの引数リストが長すぎるエラー


629

UNIXのディレクトリの下に数百のPDFがあります。PDFの名前は本当に長い(約60文字)。

次のコマンドを使用してすべてのPDFを一緒に削除しようとすると:

rm -f *.pdf

次のエラーが発生します。

/bin/rm: cannot execute [Argument list too long]

このエラーの解決策は何ですか?このエラーはmvcpコマンドでも発生しますか?はいの場合、これらのコマンドの解決方法は?


21
あなたはこのリンクが役に立つかもしれません
another.anon.coward



4
@jww:そして私は長年にわたって、bashが「プログラマーが一般的に使用するソフトウェアツール」(ここで質問できるカテゴリ)に該当すると考え続けました。
Vicky

@Nik-"スクリプトで..."を追加しても無理はありません。問題が最小、完全、検証可能な例に減少した場合、それはコマンドの実行方法に関する問題です。明らかなものがない場合は、お詫びします。
JWW

回答:


876

これが発生する理由は、bashが実際にアスタリスクを一致するすべてのファイルに展開し、非常に長いコマンドラインを生成するためです。

これを試して:

find . -name "*.pdf" -print0 | xargs -0 rm

警告:これは再帰的な検索であり、サブディレクトリ内のファイルも検索(および削除)します。-f確認したくない場合にのみ、rmコマンドを追加してください。

次のようにして、コマンドを非再帰的にすることができます。

find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm

別のオプションは、findの-deleteフラグを使用することです。

find . -name "*.pdf" -delete

7
いいえ、xargs特にリストを分割し、必要に応じていくつかのコマンドを発行します。
tripleee

7
@Dennis:-maxdepth 1パスの後の最初の引数である必要があります。
Barton Chittenden

54
Findには、-delete見つかったファイルを削除するためのフラグがあり、それができなかったとしても-exec、xargsを呼び出すのではなく、rmの実行に使用する方がよいと考えられます(これは、-deleteまたは)で2つのプロセス-exec
scragar、2014年

3
@ÉdouardLopez...しかし、これはNULL区切りの入力を読み取っています。そして全体はdangerous (broken, exploitable, etc.)、かなりばかげています。間違いなく使用するときは注意する必要がありますxargsが、それは完全ではありませんeval/evil
モニカを回復してください'25 / 07/25

4
@scragarを-exec呼び出すとrm、プロセスの数は1 +ファイルの数になりますが、これからの同時プロセスの数は2になる場合があります(findはrmプロセスを同時に実行する可能性があります)。使用xargsするプロセスの数は2 + nに劇的に減少します。ここで、nはファイルの数より少ないプロセスの数です(たとえば、ファイルの長さ/ 10ですが、パスの長さに依存します)。findが削除を直接行うと仮定すると、using -deleteが呼び出される唯一のプロセスである必要があります。
ニューラルマー2016

396

tl; dr

これは、コマンドライン引数のサイズに関するカーネルの制限です。for代わりにループを使用してください。

問題の原因

これはシステムの問題であり、関連してexecveおり、ARG_MAX不変です。これに関するドキュメントはたくさんあります(man execvedebianのwikiを参照)。

基本的に、展開により、制限を超えるコマンド(およびそのパラメーター)が生成されARG_MAXます。カーネル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 echo rm "$f"; done

そしてそれを実行します:

for f in *.pdf; do rm "$f"; done

また、グロブはシェル間で強力かつ一貫した動作をするため、これは移植可能なアプローチです(POSIX仕様の一部)。

注:いくつかのコメントで述べたように、それは、より複雑なシナリオを適応させることができますように、これは確かに遅いがより保守である例えば 1だけのワンアクションよりも多くやりたいところ。

解決策:使用 find

「NULで区切られていない入力を読み取ると危険(破損、悪用可能、など)になるため、xargs使用できますfindが、実際には使用しないでください

find . -maxdepth 1 -name '*.pdf' -delete 

-maxdepth 1 ... -delete代わりにを-exec rm {} +使用findすると、外部プロセスを使用せずに、必要なシステムコール自体を簡単に実行できるため、高速になります(@chepnerコメントのおかげ)。

参考文献


31
すばらしい答えです。これが、すべてのSOの質問に答えるべき方法です。ありがとう!
2015

1
forループについて言及する場合は+1 。find以前使っていたのですが、いつもオプションなどを忘れてしまうので、どうすればいいのか常に調べています。for私見を思い出しやすい
ロバートダンドン2017

3
for f in *; do rm "$f"; done魅力的な作品として使用
abdul qayyum 2017年

3
find -exec解決策は、はるかに速くよりであるように思わforループ。
threeve

2
5年後4.15.0で(4.15.0-1019-gcp正確には)および制限は、Linux gitのレポにARG_MAXを探し、興味深いことに2097152のままである示す結果得られ131702.であることをARG_MAXを
マット・M.

181

find-deleteアクションがあります:

find . -maxdepth 1 -name '*.pdf' -delete

4
これでも「引数リストが長すぎます」を返します。少なくとも私にとってはそうです。xargsDennisの回答に従ってを使用すると、意図したとおりに機能します。
セルジオ

7
それはfindのバグのように聞こえます。
ThiefMaster 2014年

3
@Sergioにも同じ問題があり、名前パターンの周りの引用符が欠落していることが原因でした。
Luxian

ええと、なぜものを見つけるためのツールに削除のスイッチさえあるのですか?控えめに言っても不必要で危険でもあるのは本当に私だけなのでしょうか。
mathreadler 2016年

2
@mathreadlerこれは、一般的なユースケースが一連-execのファイルを削除することであるという事実に対処します。-exec rm {} +同じことを行いますが、それでも少なくとも1つの外部プロセスを開始する必要があります。外部ラッパーを使用せずに、必要なシステムコール自体を簡単に実行-deleteできfindます。
chepner 16

21

別の答えはxargs、コマンドをバッチで処理することを強制することです。たとえば、一度にdeleteファイルに、ディレクトリ100cd入れて、これを実行します。

echo *.pdf | xargs -n 100 rm


4
Linuxでコマンドを削除する場合、これはエンジニアでミスを入力した場合に大変なことですが、これが「最も安全で、何が起こっているのかを知っている」が最善の方法だと思います。ドットをタイプし忘れると、会社が1分でクラッシュしてしまうほどの凝ったものではありません。
人工知能

1
これを特定のコマンドのデフォルトの拡張にする方法を教えてください。彼らはかつてないか(のような「RM」)でそれらすべてを必要とする場合、それが知られています良い多くの「標準」Linuxのコマンドがあります
user1212212

1
これechoはシェルが組み込まれている場所でのみ機能することに注意してください。コマンドを使用してしまった場合echoでも、プログラムの引数の制限に遭遇します。
Toby Speight

14

または、あなたは試すことができます:

find . -name '*.pdf' -exec rm -f {} \;

これにより、サブディレクトリからもファイルが削除されます。それを防ぐ方法は?
Vicky

@NikunjChauhan -maxdepthオプションを追加:find . -maxdepth 1 -name '*.pdf' -exec rm -f {} \;
Jon Lin

maxdepthオプションを挿入できない
Vicky

そのオプションは、上記の@Dennisの回答(選択した回答)のように、Linuxのみのオプションである可能性があります。
jvriesem 2014年

12

非常に多数のファイルを一度に削除しようとしている場合(私は今日485,000以上のディレクトリを削除しました)、おそらくこのエラーに遭遇します:

/bin/rm: Argument list too long.

問題は、のようなものを入力するとrm -rf **「rm -rf file1 file2 file3 file4」のように、一致するすべてのファイルのリストに置き換えられることです。この引数のリストを格納するために割り当てられたメモリの比較的小さなバッファがあり、それがいっぱいになると、シェルはプログラムを実行しません。

この問題を回避するには、多くの人がfindコマンドを使用してすべてのファイルを検索し、次のように1つずつ「rm」コマンドに渡します。

find . -type f -exec rm -v {} \;

私の問題は、500,000のファイルを削除する必要があり、時間がかかりすぎていたことです。

ファイルを削除するはるかに高速な方法を偶然見つけました。「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

ありがとう。sudo find . -type f -delete約485千のファイルを削除しましたが、うまくいきました。約20秒かかりました。
Nigel Alderton、2018

11

あなたはこれを試すことができます:

for f in *.pdf
do
  rm $f
done

編集:ThiefMasterのコメントは、若いシェルのjedisにそのような危険な慣行を開示しないように私に提案しているので、より「安全な」バージョンを追加します(誰かが「-rf。..pdf」ファイルを持っているときに物事を保存するため)

echo "# Whooooo" > /tmp/dummy.sh
for f in '*.pdf'
do
   echo "rm -i $f" >> /tmp/dummy.sh
done

上記を実行した後、お気に入りの/tmp/dummy.shファイルを開きます。エディターで危険なファイル名がないかすべての行をチェックし、見つかった場合はコメントアウトします

次に、ダミーの.shスクリプトを作業ディレクトリにコピーして実行します。

これはすべてセキュリティ上の理由からです。


5
これは、egという名前のファイルで本当に良いことになると思います-rf .. .pdf
ThiefMaster

はい、そうですが、一般的にシェルで使用される場合、コマンドの発行者は彼が何をしているのかを見るはずです:)。実際には、ファイルにリダイレクトしてから、すべての行を検査することを好みます。
BigMike

2
これは "$ f"を引用しません。それがThiefMasterが話していたことです。 -rfはに優先する-iため、2番目のバージョンは(手動検査なしで)優れていません。また、すべてのファイルを要求するプロンプトが表示されるため、基本的に一括削除には役に立ちません。
Peter Cordes、2015

7

あなたはbash配列を使うことができます:

files=(*.pdf)
for((I=0;I<${#files[@]};I+=1000)); do
    rm -f "${files[@]:I:1000}"
done

この方法では、ステップごとに1000ファイルのバッチで消去されます。


2
多数のファイルの場合、これはかなり高速に見える
James Tocknell


4

rmコマンドを使用すると、同時に削除できるファイルの制限があります。

rmコマンドを複数回使用してそれらを削除できる1つの可能性は、次のようなファイルパターンに基づいています

rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf

また、findコマンドを使用して削除することもできます

find . -name "*.pdf" -exec rm {} \;

3
いいえ、rm処理するファイル数にそのような制限はありません(ただし、を超えることはargcできませんINT_MAX)。これは、引数配列全体の最大サイズに対するカーネルの制限です(そのため、ファイル名の長さが重要になります)。
Toby Speight

3

それらがスペースまたは特殊文字を含むファイル名である場合は、以下を使用します。

find -maxdepth 1 -name '*.pdf' -exec rm "{}" \;

この文は、現在のディレクトリ(-maxdepth 1)にある拡張子pdf(-name '* .pdf')のすべてのファイルを検索し、各ファイルを削除します(-exec rm "{}")。

式{}はファイル名を置き換え、 "{}"はスペースまたは特殊文字を含む文字列としてファイル名を設定します。


このコードスニペットは、問題解決する方法理由の説明を含む質問を解決する可能性がありますが、投稿の品質を向上させるのに役立ちます。あなたが今尋ねている人だけでなく、将来の読者のための質問に答えていることを忘れないでください!回答を編集して説明を追加し、適用される制限と前提を示してください。
Toby Speight 2016

重要なの-execは、シェルを呼び出さないことです。ここでの引用は、何の役にも立たない。(これらは、このコマンドを入力するシェル内の文字列でのワイルドカード拡張とトークン分割を防止しますが、文字列に{}は空白またはシェルワイルドカード文字が含まれていません。)
tripleee

2

フォームのソースディレクトリを宛先にコピーしているときに同じ問題に直面していました

ソースディレクトリにファイルが3つまでありました

はオプション-rでcpを使用し、それは私のために働いた

cp -r abc / def /

引数リストが長すぎるという警告を出さずに、abcからdefにすべてのファイルをコピーします


それについてコメントすることさえせずに誰かがなぜこれに反対票を投じたのか私にはわかりません(それはポリシーです、皆さん!)。私はフォルダー内のすべてのファイルを削除する必要がありました(問題はPDFに特に関係ありません)。そのため、このトリックはうまく機能しています。最後に行う必要があるのは、削除されたフォルダーを再作成することです。 。私は`のrm -R /パス/に/フォルダ」を使用
トーマスTempelmann

1
これは、OPの場合、*を使用していたので機能します。これは、.pdfの膨大なリストに拡張され、ディレクトリを指定すると、これが内部で処理されるため、OPの問題に対処する必要がないためです。そのため、反対票が投じられたと思います。彼のディレクトリにネストされたディレクトリまたは他のファイル(pdfではない)がある場合、OPに使用できない可能性があります
Alvein

2

これも試してください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日以上ギズしたい場合

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 {} \;

2

ulimitここに答えがないことに驚いています。この問題が発生するたびに、私はここまたはここに行き着きます。このソリューションには制限があることを理解していますがulimit -s 65536、多くの場合私にとってはうまくいくようです。


1

一時的に増加する一時的な画像でいっぱいのフォルダーで同じ問題があり、このコマンドはフォルダーをクリアするのに役立ちました

find . -name "*.png" -mtime +50 -exec rm {} \;

他のコマンドとの違いは、X日よりも古いファイル(例では50日)のみを取るmtimeパラメーターです。

それを複数回使用して、実行ごとに日の範囲を減らし、不要なファイルをすべて削除することができました


1

私はこれを回避する方法を知っているだけです。アイデアは、あなたが持っているPDFファイルのリストをファイルにエクスポートすることです。次に、そのファイルをいくつかの部分に分割します。次に、各部分にリストされているPDFファイルを削除します。

ls | grep .pdf > list.txt
wc -l list.txt

wc -lは、list.txtに含まれる行数をカウントします。それがどのくらいの長さであるかがわかったら、それを半分、4つ、または何かに分割することを決定できます。split -lコマンドの使用たとえば、それぞれを600行に分割します。

split -l 600 list.txt

これにより、xaa、xab、xacという名前のファイルがいくつか作成されます。分割方法によって異なります。これらのファイルの各リストをコマンドrmに「インポート」するには、次のコマンドを使用します。

rm $(<xaa)
rm $(<xab)
rm $(<xac)

私の悪い英語でごめんなさい。


5
名前の付いたファイルがある場合、pdf_format_sucks.docxこれも削除されます... ;-) PDFファイルをgrepする場合は、適切で正確な正規表現を使用する必要があります。
FooF 2013年

1
より良いですが、still_pdf_format_sucks.docx削除されます。正規表現のドット.は、".pdf"任意の文字と一致します。の"[.]pdf$"代わりに私はお勧めします.pdf
FooF 2016年

1

私はこの問題に数回遭遇しました。ソリューションの多くは、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')

これは私にとって非常にうまくいきました。フォルダー内の200万を超える一時ファイルを約15分でクリアすることができました。ほんの少しのコードからtarにコメントを付けたので、Pythonの知識が最小限またはまったくない人でもこのコードを操作できます。


1

そしてもう一つ:

cd  /path/to/pdf
printf "%s\0" *.[Pp][Dd][Ff] | xargs -0 rm

printfシェル組み込みであり、私が知る限り、常にそうでした。これprintfがシェルコマンドではなく(組み込み)であることを考えると、「argument list too long ...」致命的なエラーの影響を受けません。

したがって*.[Pp][Dd][Ff]、のようなシェルグロビングパターンで安全に使用できます。次に、その出力をパイプラインで削除(rm)コマンドに渡しますxargs。これにより、コマンドラインで十分なファイル名に適合し、コマンドが失敗しないようにしますrm。これはシェルです。コマンド。

\0printfそれまでに処理されWICHファイル名のヌルセパレータとして機能するxargs(それを使用して、コマンド-0セパレータとして)ので、rm空白またはファイル名に他の特殊文字がある場合に失敗しません。


1
このコードスニペットは、問題解決する方法理由の説明を含む質問を解決する可能性がありますが、投稿の品質を向上させるのに役立ちます。あなたが今尋ねている人だけでなく、将来の読者のための質問に答えていることを忘れないでください!回答を編集して説明を追加し、適用される制限と前提を示してください。
Toby Speight

特に、printfが組み込みシェルでない場合は、同じ制限が適用されます。
Toby Speight

0

一時フォルダーを作成し、保持するすべてのファイルとサブフォルダーを一時フォルダーに移動してから、古いフォルダーを削除し、一時フォルダーの名前を古いフォルダーに変更して、信頼できる状態になるまでこの例を試してください。

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


0

*.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/

。。。

rsyncハックの詳細については、rsyncのヒントとコツをクリックしてください


0

非常に大きなファイルのリスト(> 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 __name__ == '__main__':
    for file_name in files_names:
        print(file_name)
        pool.apply_async(delete_files,[file_name], error_callback=callback_error)

0

すべてのiノードをいっぱいにするアプリケーションによって作成された無数の無用のログファイルがあったときに、私は同様の問題に直面しました。私は「ロケート」に頼り、すべてのファイルを「ロケート」してテキストファイルにし、1つずつ削除しました。しばらくかかりましたが、仕事をしました!


これはかなりあいまいでありlocate、ディスクに空きがあるときにインストールし直す必要があります。
tripleee

-2

xargsを使用するよりも少し安全なバージョンで、再帰的でもありません。 ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done

'rm'はディレクトリを削除しないので、ここでディレクトリをフィルタリングすることは少し不要ですが、簡単にするために削除できますが、なぜエラーを返すものを実行するのでしょうか。


3
これはまったく安全ではなく、改行が含まれているファイル名では機能せず、明らかなコーナーケースを1つ指摘します。 解析lsは一般的には避けなければならない一般的なアンチパターンであり、多くのバグがここに追加されます。grep | grepただ非常にエレガントではありません。
tripleee 2016年

とにかく、これは複雑な解決策を必要とする新しくてエキゾチックな問題ではないようです。での答えfindは良く、ここや他の場所で十分に文書化されています。このトピックおよび関連トピックの詳細については、たとえばmywiki.wooledge.orgを参照してください。
Tripleee 2016年

-2

GNU並列(sudo apt install parallel)の使用は非常に簡単です

マルチスレッドのコマンドを実行します。ここで、「{}」は渡された引数です

例えば

ls /tmp/myfiles* | parallel 'rm {}'


わかりませんが、出力lsを他のコマンドに直接渡すのは危険なアンチパターンであるためだと思います。つまり、ワイルドカードを展開すると、実行時lsに元のrmコマンドで経験したのと同じエラーが発生するという事実です。。
Toby Speight

そのコンテキストについては、ParsingLsを参照してください。そしてparallel、複雑さを回避することを好む一部の人々を不快にします-内面を見ると、それはかなり不透明です。StepsaneUnixおよびLinuxのStackExchange greybeardsの1つ)とOle Tange(Parallelの作者)の間の、lists.gnu.org / archive / html / bug -parallel / 2015-05 / msg00005.htmlにあるメーリングリストのスレッドを参照してください。xargs -P並列化も行いますが、可動部分が少なく、より単純で無駄のない方法で行われるため、動作の予測と推論がはるかに容易になります。
Charles Duffy

-2

最初の100ファイルを削除するには:

rm -rf 'ls | 頭-100 '


2
危険(または、明らかに意図したとおりにバッククォートを使用した場合)-ファイル名にスペースを含むシェルのメタ文字が含まれている場合、結果は意図したものとは異なります。
Toby Speight

-5

以下のオプションは、この問題に対して単純なようです。他のスレッドからこの情報を入手しましたが、役に立ちました。

for file in /usr/op/data/Software/temp/application/openpages-storage/*; do
    cp "$file" /opt/sw/op-storage/
done

上記の1つのコマンドを実行するだけで、タスクが実行されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.