слишком длинный список аргументов для команд rm, cp, mv

<p>у меня есть несколько сотен pdf-файлов в каталоге в unix. названия pdf-файлов действительно длинные (около 60 символов).</p><p>когда я пытаюсь удалить все pdf-файлы вместе, используя следующую команду:</p><pre><code>rm -f *.pdf </code></pre><p>я получаю следующую ошибку:</p><pre><code>/bin/rm: cannot execute [argument list too long] </code></pre><p>как решить эту ошибку? эта ошибка возникает также для команд <code>mv</code> и <code>cp</code>? если да, как решить для этих команд?</p>

<p>причина этого заключается в том, что bash фактически расширяет звездочку на каждый соответствующий файл, создавая очень длинную командную строку.</p><p>попробуй это:</p><pre><code>find . -name "*.pdf" -print0 | xargs -0 rm </code></pre><p><strong> предупреждение: </strong>это рекурсивный поиск, который также найдет (и удалит) файлы в подкаталогах. прикрепите <code>-f</code> к команде rm, только если вы уверены, что не хотите подтверждения.</p><p>чтобы сделать команду нерекурсивной, вы можете сделать следующее:</p><pre><code>find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm </code></pre><p>другой вариант - использовать флаг <code>-delete</code> команды find:</p><pre><code>find . -name "*.pdf" -delete </code></pre>

<h2>тл; др</h2><p>это ограничение ядра на размер аргумента командной строки. вместо этого используйте цикл <code>for</code>.</p><h2>происхождение проблемы</h2><p>это системная проблема, связанная с константами <code>execve</code> и <code>arg\_max</code>. об этом много документации (см. <a href="http://linux.die.net/man/2/execve">man execve</a> , <a href="https://wiki.debian.org/commonerrormessages/argumentlisttoolong">вики debian</a> ). </p><p>по сути, расширение создает команду <em>command</em> (с ее параметрами), которая превышает предел <code>arg\_max</code> . в ядре <code>2.6.23</code> предел был установлен равным <code>128 kb</code>. эта константа была увеличена, и вы можете получить ее значение, выполнив:</p><pre class="lang-sh prettyprint-override"><code>getconf arg\_max # 2097152 # on 3.5.0-40-generic </code></pre><h2>решение: использование <code>for</code> loop</h2><p>используйте цикл <code>for</code>, как это рекомендовано для <a href="http://mywiki.wooledge.org/bashfaq/095">bashfaq/095</a> , и нет ограничений, кроме как для озу/памяти:</p><pre><code>for f in *.pdf; do rm "$f"; done также это переносимый подход, поскольку у glob сильное и согласованное поведение среди оболочек ( <a href="http://man7.org/linux/man-pages/man7/glob.7.html">часть спецификации posix ). <strong>примечание:</strong> как отмечается в нескольких комментариях, это действительно медленнее, но более легко обслуживаемо, поскольку может адаптировать более сложные сценарии, например. где каждый хочет сделать больше, чем просто одно действие.решение: использование findесли вы настаиваете, вы можете использовать find, но на самом деле <strong>не использовать xargs</strong>, так как "опасно (сломано, может быть использовано и т.д.) при чтении ввода без разделителей nul":find . -maxdepth 1 -name '.pdf' -delete использование -maxdepth 1 ... -delete вместо -exec rm {} + позволяет find просто выполнять необходимые системные вызовы самостоятельно, без использования внешнего процесса, а значит, быстрее (благодаря <a href="https://stackoverflow.com/questions/11289551/argument-list-too-long-error-for-rm-cp-mv-commands/18647755?noredirect=1#comment69166385_11302033">@chepner comment ).рекомендации  <a href="http://mywiki.wooledge.org/bashfaq/095">я получаю «список аргументов слишком долго». как я могу обработать большой список кусками? @ wooledge  <a href="http://linux.die.net/man/2/execve">execve (2) - страница справочника linux (поиск arg_max);  <a href="https://wiki.debian.org/commonerrormessages/argumentlisttoolong">ошибка: список аргументов слишком длинный @ вики debian;  <a href="https://superuser.com/questions/240183/how-to-work-around-shell-limitation-of-argument-list-too-long%29">почему я получаю «/ bin/sh: список аргументов слишком длинный» при передаче аргументов в кавычках? @ superuser 

find имеет действие -delete:find . -maxdepth 1 -name '.pdf' -delete 

другой ответ - заставить xargs обрабатывать команды в пакетном режиме. например, delete файлы 100 одновременно, cd в каталог и запустите это:echo .pdf | xargs -n 100 rm

или вы можете попробовать:find . -name '.pdf' -exec rm -f {} ; 

вы можете попробовать это:for f in .pdf do rm $f done </code></pre><p>правка: комментарий thiefmaster предлагает мне не раскрывать такую опасную практику для джедаев молодого шелл, поэтому я добавлю более «более безопасную» версию (ради сохранения вещей, когда у кого-то есть «-rf. ..pdf»). файл)</p><pre><code>echo "# whooooo" > /tmp/dummy.sh for f in '*.pdf' do echo "rm -i $f" >> /tmp/dummy.sh done после запуска вышеприведенного, просто откройте файл /tmp/dummy.sh в вашем фаворе. редактировать и проверять каждую строку на наличие опасных имен файлов, комментируя их, если они найдены.затем скопируйте скрипт dummy.sh в рабочий каталог и запустите его.все это по соображениям безопасности.

если вы пытаетесь удалить очень большое количество файлов за один раз (сегодня я удалил каталог с 485 000+), вы, вероятно, столкнетесь с этой ошибкой:/bin/rm: argument list too long. проблема в том, что когда вы набираете что-то вроде rm -rf ,  заменяется списком каждого соответствующего файла, например, «rm -rf file1 file2 file3 file4» и так далее. для хранения этого списка аргументов имеется относительно небольшой буфер памяти, и, если он заполнен, оболочка не выполнит программу.чтобы обойти эту проблему, многие люди используют команду find, чтобы найти каждый файл и передать их один за другим команде «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 

вы можете использовать массив bash:<pre class="lang-bash prettyprint-override">files=(.pdf) for((i=0;i<${#files[*]};i+=1000)); do rm -f ${files[@]:i:1000}; done таким образом, он будет стирать партиями по 1000 файлов за шаг.

вы можете использовать эту рекомендацию find -name ".pdf" -delete 

find . -type f -name 'xxx' -print -delete

команда rm имеет ограничение на количество файлов, которые вы можете удалить одновременно.одна из возможностей, которую вы можете удалить, используя несколько раз команду rm, основана на ваших шаблонах файлов, например:rm -f a.pdf rm -f b.pdf rm -f c.pdf ... rm -f .pdf вы также можете удалить их через команду find:find . -name ".pdf" -exec rm {} ; 

если это имена файлов с пробелами или специальными символами, используйте:find -maxdepth 1 -name '.pdf' -exec rm "{}" ; это предложение ищет все файлы в текущем каталоге (-maxdepth 1) с расширением pdf (-name ' .pdf'), а затем удаляет каждый из них (-exec rm "{}").выражение {} заменяет имя файла, а "{}" задает имя файла в виде строки, включая пробелы или специальные символы.

я столкнулся с той же проблемой при копировании исходного каталога формы в место назначенияисходный каталог имел файлы ~ 3 lakcsя использовал<strong> cp с опцией -r </strong>и это работает для меня<strong> cp -r abc/def/</strong>он скопирует все файлы из abc в def без предупреждения о слишком длинном списке аргументов

и еще один:cd /path/to/pdf printf "%s0" .[pp][dd][ff] | xargs -0 rm printf - это встроенная оболочка, и, насколько я знаю, она всегда была таковой. теперь, учитывая, что printf не является командой shell (но является встроенной), она не подвержена фатальной ошибке «argument list too long ...».таким образом, мы можем безопасно использовать его с шаблонами глобализации shell, такими как .[pp][dd][ff], затем передаем по выводу команду на удаление (rm) через xargs, чтобы убедиться, что он соответствует достаточному количеству имен файлов в командной строке, чтобы не пропустить команду rm, которая является командой shell.0 в printf служит нулевым разделителем для имен файлов, которые затем обрабатываются командой xargs, используя его (-0) в качестве разделителя, поэтому rm не завершается ошибкой, если в именах файлов есть пробелы или другие специальные символы. 

я удивлен, что здесь нет ulimit ответов. каждый раз, когда у меня возникает эта проблема, я в конечном итоге <a href="https://unix.stackexchange.com/questions/128559/solving-mv-argument-list-too-long">здесь или <a href="https://unix.stackexchange.com/questions/45583/argument-list-too-long-how-do-i-deal-with-it-without-changing-my-command">здесь . я понимаю, что это решение имеет ограничения, но ulimit -s 65536, кажется, часто помогает мне.

я столкнулся с этой проблемой несколько раз. многие из решений будут запускать команду rm для каждого отдельного файла, который необходимо удалить. это очень неэффективно:<pre class="lang-sh prettyprint-override">find . -name ".pdf" -print0 | xargs -0 rm -rf в итоге я написал скрипт на python для удаления файлов на основе первых 4 символов в имени файла:<pre class="lang-python prettyprint-override">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') это сработало очень хорошо для меня. мне удалось очистить более 2 миллионов временных файлов в папке примерно за 15 минут. я прокомментировал 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  -type f -mtime +90 -exec rm -rf {} ; пример: только для последних 30-дневных файлов, которые вы хотите удалить, используйте команду ниже (-)find  -type f -mtime -30 -exec rm -rf {} ; если вы хотите посмотреть файлы более чем на 2 дняfind  -type f -mtime +2 -exec gzip {} ; если вы хотите видеть файлы/папки только за последний месяц .......find  -type f -mtime -30 -exec ls -lrt {} ; более 30 дней больше, чем только список файлов/папок пример:find  -type f -mtime +30 -exec ls -lrt {} ; find /opt/app/logs -type f -mtime +30 -exec ls -lrt {} ; 

я столкнулся с подобной проблемой, когда приложение создавало миллионы бесполезных файлов журналов, которые заполняли все иноды. я прибег к «locate», собрал все файлы, «расположенные» d, в текстовый файл, а затем удалил их один за другим. потребовалось время, но сделал работу!

я знаю только способ обойти это .. идея состоит в том, чтобы экспортировать этот список 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) </code></pre><p>извините за мой плохой английский.</p>

<p>я обнаружил, что для очень больших списков файлов (> 1e6) эти ответы были слишком медленными. вот решение с использованием параллельной обработки в python. я знаю, я знаю, это не linux ... но здесь ничего не работает. </p><p>(это спасло меня часы)</p><pre class="lang-python prettyprint-override"><code># 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) </code></pre>

<p>удалить все <code>*.pdf</code> в директории <code>/path/to/dir\_with\_pdf\_files/</code></p><pre><code>mkdir empty\_dir # create temp empty dir rsync -avh --delete --include '*.pdf' empty\_dir/ /path/to/dir\_with\_pdf\_files/ </code></pre><hr><p>удаление определенных файлов с помощью <code>rsync</code> с использованием подстановочного знака, возможно, является самым быстрым решением, если у вас миллионы файлов. и это позаботится об ошибке, которую вы получаете.</p><hr><p>(необязательный шаг): dry run. чтобы проверить, что будет удалено без удаления. `</p><pre><code>rsync -avhn --delete --include '*.pdf' empty\_dir/ /path/to/dir\_with\_pdf\_files/ </code></pre><p>. . .</p><p>нажмите <a href="https://www.quora.com/what-are-some-rsync-hacks/answer/raman-kathpalia?share=68335132&srid=hfe13">советы и рекомендации по rsync</a> для получения дополнительной информации о взломах rsync</p>

<p>если вам нужно сохранить сервер или систему<strong> отзывчивыми </strong>при удалении огромного количества файлов, <code>sleep</code> между каждым оператором удаления может быть хорошим подходом.</p><pre><code>find . -name "*.pdf" -print0 | while read -d $'0' file do rm "$file" sleep 0.005 # sleeps for 5ms, tweak as needed done </code></pre>