На серверах могут скапливаться горы файлов, которые периодически нужно удалять. Например, логи, скомпилированные версии файлов, или любой другой файловый кеш, генерируемый скриптами.

Рано или поздно эти горы приходится вычищать:

$ rm /tmp/logs/*.log

Если количество файлов будет критично большим, в какой-то момент вместо удаления файлов мы увидим такое сообщение в консоли:

/bin/rm: Argument list too long.

Что это означает?

Проблема

Дело в том, что использование маски в командах типа rm/cp/find линукс переводит в удобный для себя формат, делая из понятной человеку команде:

$ rm /tmp/logs/*.log

список файлов под этой маской:

$ rm /tmp/logs/1.log /tmp/logs/2.log /tmp/logs/3.log ...

Проблемы начинаются, когда аргументов у команды rm становится больше допустимого лимита. Проверить этот лимит можно с помощью команды getconf:

$ getconf ARG_MAX
262144

И что все-таки делать?

Использовать цикл For

Самый простой способ — выполнить нужную нам команду в цикле for, у которого есть два важных преимущества. Во-первых, циклы нересурсоемкие и не имеют лимитов на количество аргументов. Во-вторых, в цикл просто завернуть дополнительную логику, если потребуется делать что-то сложнее, чем удаление файлов.

Например, вот так можно удалить все файлы одной командой:

$ for f in /tmp/logs/*.log; do rm "$f"; done

Или удалить файлы, которые старше семи дней:

for f in /tmp/logs/*.log
do
  find $f -mtime +7 -exec rm {} \;
done

Или посчитать, записать в переменную и вывести их количество:

FILES_COUNT=`c=0; for f in /tmp/logs/*.log ; do ((c++)); done ; echo $c`
echo "$FILES_COUNT log files left";

Самое главное

  • не забывайте чистить логи регулярно, чтобы не засорять файловую систему
  • используйте для этого готовые инструменты, чтобы не придумывать свои велосипеды
  • перечитывайте команды перед выполнением, чтобы случайно не удалить всё