У меня есть несколько сотен PDF файлов под каталогом в UNIX. Имена файлов PDF очень длинные (около 60 символов).
Когда я пытаюсь удалить все файлы PDF вместе, используя следующую команду:
rm -f *.pdf
Я получаю следующую ошибку:
/bin/rm: cannot execute [Argument list too long]
Каково решение этой ошибки?
Происходит ли эта ошибка для команд mv
и cp
? Если да, как решить эту команду?
Причина этого в том, что bash фактически расширяет звездочку для каждого соответствующего файла, создавая очень длинную командную строку.
Попробуйте следующее:
find . -name "*.pdf" -print0 | xargs -0 rm
Предупреждение:. Это рекурсивный поиск и поиск (и удаление) файлов в подкаталогах. Tack on -f
в команду rm, только если вы уверены, что не хотите подтверждения.
Если вы работаете в Linux, вы можете сделать следующее, чтобы сделать команду нерекурсивной:
find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm
Другой вариант - использовать флаг -delete
:
find . -name "*.pdf" -delete
xargs
специально разбивает список и при необходимости выдает несколько команд.
Это ограничение ядра по размеру аргумента командной строки. Вместо этого используйте цикл for
.
Это системная проблема, связанная с константой execve
и ARG_MAX
. Существует много документации по этому поводу (см. man execve, debian wiki).
В принципе, расширение создает команду (с ее параметрами), которая превышает предел ARG_MAX
.
В ядре 2.6.23
предел был установлен в 128 kB
. Эта константа была увеличена, и вы можете получить ее значение, выполнив:
getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic
Используйте цикл for
, как рекомендуется на BashFAQ/095, и нет ограничений, кроме RAM/памяти:
for f in *.pdf; do rm "$f"; done
Также это переносимый подход, поскольку glob имеет сильное и последовательное поведение среди оболочек (часть спецификации POSIX).
Если вы настаиваете, вы можете использовать find
, но на самом деле не использовать xargs, поскольку он "опасен (сломан, эксплуатируется и т.д.) при чтении не-NUL-ограниченного ввода":
find . -name '*.pdf' -exec rm {} +
for
. Раньше я использовал find
, но я всегда смотрю, как это сделать, так как я постоянно забываю опции и т. Д. for
кажется легче вспомнить ИМХО
find
имеет действие -delete
:
find . -maxdepth 1 -name '*.pdf' -delete
xargs
, согласно ответу Денниса, работает как задумано.
Другой ответ - заставить xargs
обрабатывать команды в партиях. Например, в delete
файлы 100
за раз, cd
в каталог и запустите это:
echo *.pdf | xargs -n 100 rm
Или вы можете попробовать:
find . -name '*.pdf' -exec rm -f {} \;
find . -maxdepth 1 -name '*.pdf' -exec rm -f {} \;
Вы можете использовать массив bash:
files=(*.pdf)
for((I=0;I<${#files[*]};I+=1000)); do rm -f ${files[@]:I:1000}; done
Таким образом, он будет удалять пакеты по 1000 файлов на каждый шаг.
вы можете использовать эту оценку
find -name "*.pdf" -delete
вы можете попробовать следующее:
for f in *.pdf
do
rm $f
done
EDIT: Комментарий 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 в своем fav. редактор и проверять каждую строку для опасных имен файлов, комментируя их, если они найдены.
Затем скопируйте dummy.sh script в свой рабочий каталог и запустите его.
Все это по соображениям безопасности.
-rf .. .pdf
Если они являются именами файлов с пробелами или специальными символами, используйте:
find -maxdepth 1 -name '*.pdf' -exec rm "{}" \;
Это предложение ищет все файлы в текущем каталоге (-maxdepth 1) с расширением pdf (-name '*.pdf'), а затем удаляет каждый из них (-exec rm "{}" ).
Выражение {} заменит имя файла, а "{}" задает имя файла как строку, включая пробелы или специальные символы.
Команда rm имеет ограничение на файлы, которые вы можете удалить одновременно.
Одна возможность вы можете удалить их, используя несколько раз базы команд rm в ваших шаблонах файлов, например:
rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf
Вы также можете удалить их через команду find:
find . -name "*.pdf" -exec rm {} \;
rm
не имеет такого ограничения на количество файлов, которые он будет обрабатывать (кроме того, его argc
не может быть больше, чем INT_MAX
). Это ограничение ядра на максимальный размер всего массива аргументов (поэтому длина имен файлов значительна).
i столкнулась с такой же проблемой при копировании исходного каталога исходного кода в пункт назначения
исходный каталог имел файлы ~ 3 lakcs
я использовал cp с опцией -r, и это сработало для меня
cp -r abc/def/
он скопирует все файлы из abc в def без слишком долгого предупреждения о списке аргументов
Я столкнулся с этой проблемой несколько раз. Многие из решений будут запускать команду rm
для каждого отдельного файла, который необходимо удалить. Это очень неэффективно:
find . -name "*.pdf" -print0 | xargs -0 rm -rf
В итоге я написал python script для удаления файлов на основе первых 4 символов в имени файла:
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 000 файлов temp в папке примерно через 15 минут. Я прокомментировал tar из небольшого числа кода, поэтому любой, обладающий минимальным знанием питона, может манипулировать этим кодом.
Попробуйте это также. Если вы хотите удалить более 30/90 дней (+) или еще ниже 30/90 (-) дней файлов/папок, вы можете использовать приведенные ниже команды ex
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 {} \;
Если вы хотите giz файлы для файлов более чем на 2 дня
find <path> -type f -mtime +2 -exec gzip {} \;
Если вы хотите просмотреть файлы/папки только за последний месяц. Пример:
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 {} \;
Я обнаружил, что для чрезвычайно больших списков файлов ( > 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)
Я знаю только об этом. Идея состоит в том, чтобы экспортировать этот список файлов 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)
Извините за мой плохой английский.
pdf_format_sucks.docx
он также будет удален ... ;-) Вы должны использовать правильное и точное регулярное выражение при подборе файлов pdf.
И еще один:
cd /path/to/pdf
printf "%s\0" *.[Pp][Dd][Ff] | xargs -0 rm
printf
не является встроенной оболочкой, на него распространяются те же ограничения.
Использование GNU parallel (sudo apt install parallel
) очень просто
Он выполняет команды многопоточности, где '{}' - это аргумент, переданный
например.
ls /tmp/myfiles* | parallel 'rm {}'
ls
напрямую другим командам является опасным антипаттерном, и тот факт, что расширение подстановочного знака вызовет тот же сбой при выполнении ls
как и в оригинальная команда rm
.
Если у вас есть похожие проблемы с grep, самым простым решением является переход на один каталог обратно и выполнение рекурсивного поиска.
Итак, вместо
grep "something" *
вы можете использовать:
cd ..
grep "something" -R search_in_this_dir/
Обратите внимание, что он также будет рекурсивно искать подпапки в каталоге "search_in_this_dir".
Более безопасная версия, чем использование xargs, также не рекурсивная:
ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done
Фильтрация наших каталогов здесь немного не нужна, так как "rm" в любом случае не удалит ее, и ее можно удалить для простоты, но зачем запускать что-то, что обязательно вернет ошибку?
ls
является распространенным антипаттерном, которого определенно следует избегать, и добавляет сюда ряд дополнительных ошибок. grep | grep
просто не очень элегантный.
find
хороши и хорошо документированы здесь и в других местах. См., Например, mywiki.wooledge.org, чтобы узнать больше об этой и смежных темах.
У меня была та же проблема с папкой, полной временных изображений, которые росли день ото дня, и эта команда помогла мне очистить папку
find . -name "*.png" -mtime +50 -exec rm {} \;
Разница с другими командами - это параметр mtime, который будет принимать только файлы старше X дней (в примере 50 дней)
Используя это несколько раз, уменьшая при каждом выполнении дневной диапазон, я смог удалить все ненужные файлы
Предположим, что введено имя входного каталога и выведено имя выходного каталога. Затем вы можете использовать простой цикл для копирования всех
for f in input/*
do
cp $f output
done
Этот параметр кажется простым для этой проблемы. Я получил эту информацию из какой-то другой темы, но это помогло мне.
for file in /usr/op/data/Software/temp/application/openpages-storage/*; do
cp "$file" /opt/sw/op-storage/
done
Просто запустите указанную выше команду, и она выполнит задачу.