Какой быстрый и не слишком сложный способ удалить все файлы в каталоге длиной менее x строк в bash?
Вот решение POSIX, которое должно быть довольно простым для понимания:
find . -type f -exec awk -v x=10 'NR==x{exit 1}' {} \; -exec echo rm -f {} \;
Как и в ответе Стефана , удалите, echo
когда довольны тем, что будет удалено.
Точка .
представляет текущий каталог. find
рекурсивно находит файлы и каталоги .
и может что-то с ними делать.
-type
является одним из find
«S праймериз ; это тест, который будет выполняться для каждого файла и каталога, которые рекурсивно найдены (внутри .
), а остальные основные цвета в строке оцениваются только в том случае, если это приводит к значению "true".
В этом конкретном случае мы продолжаем, только если имеем дело с обычным файлом , а не каталогом или чем-то еще (например, блочным устройством).
-exec
Первичные (из find
) вызывает внешнюю команду, и только переходит к следующему первичным , если внешняя команда завершается успешно (статус выхода «0»). {}
Заменяется именем файла быть «считается» по find
команде. Таким образом, первый -exec
вызов эквивалентен следующей команде оболочки, выполняемой для каждого файла по очереди:
awk -v x=10 'NR==x{exit 1}' ./somefilename
Awk - это целый язык, разработанный для обработки текстовых файлов с разделителями, таких как CSV. Условные выражения и команды Awk (которые заключаются в одинарные кавычки и начинаются с букв NR
) выполняются для каждой строки текстового файла. (Неявное зацикливание.)
Чтобы полностью изучить Awk, я настоятельно рекомендую Учебное пособие по Grymoire , но я объясню функции Awk, используемые в приведенной выше команде.
-v
Флаг Awk позволяет установить переменную Awk (один раз) перед командами Awk выполняются (для каждой строки файла.) В этом случае мы устанавливаем x
в 10
.
NR
это специальная переменная Awk со ссылкой на « N умбры текущего R ecord.» Другими словами, это номер строки, который мы просматриваем в каждом конкретном проходе цикла.
(Обратите внимание , что это возможно, хотя и необычно, чтобы использовать другой « R ecord S eparator» , чем значение по умолчанию символа новой строки, с помощью настройки RS
. Вот пример игры с рекордными сепараторами. )
Сценарии Awk обычно состоят из условий (вне фигурных скобок) в сочетании с действиями (внутри фигурных скобок). Могут быть составные условия и составные действия, и есть условие по умолчанию (true) и действие по умолчанию (print), но нам не нужно не заморачивайся с теми.
Условие здесь, «Является ли это 10 - й линии?» Если это так, мы завершаем работу с ненулевым состоянием выхода, что в сценариях оболочки означает «неудачное завершение команды».
Таким образом, единственная возможность успешного завершения этой команды Awk - это достижение конца файла до достижения 10-й строки.
Таким образом, если скрипт Awk завершается успешно, это означает, что у вас файл менее десяти строк.
Следующий -exec
вызов (если вы удалите echo
) удалит каждый файл (который заходит так далеко при оценке find
основных цветов), выполнив:
rm -f ./somefilename
Предполагая find
реализацию, которая поддерживает -readable
предикат (если ваш find
не поддерживает его, просто удалите его, вы просто получите сообщения об ошибках для нечитаемых файлов или замените их на -exec test -r {} \;
):
x=10 find . -type f -readable -exec sh -c '
for file do
lines=$(wc -l < "$file") && [ "$((lines))" -lt "$x" ] && echo rm -f "$file"
done' sh {} +
Уберите echo
если счастлив.
Это не особенно эффективно в том , что он считает все строки в каждом файле в то время как это нужно только остановиться на x
м один и он работает один wc
(и , возможно , один rm
) команду для каждого файла.
С GNU awk
вы можете сделать это намного эффективнее с:
x=10
find . -type f -readable -exec awk -v x="$x" -v ORS='\0' '
FNR == x {nextfile}
ENDFILE {if (FNR < x) print FILENAME}' {} +|
xargs -r0 echo rm -f
(опять удаляй echo
когда доволен).
То же самое с perl
:
x=10 find . -type f -readable -exec perl -Tlne '
if ($. == $ENV{x}) {close ARGV}
elsif (eof) {print $ARGV; close ARGV}' {} +
Заменить print
с , unlink
если счастлив.
sh
? 2.wc -l < "$file"
Быстрее чемwc -l "$file"
? 3. Откуда sh знает значение$x
, которое определяется в вызывающей оболочке Bash?sh
, что входит в этот встроенный скрипт$0
, который будет использоваться, например, для сообщений об ошибках.wc -l "$file"
напечатает имя файла, который нам здесь не нужен, и запустится,wc
даже если файл не может быть открыт.$x
экспортируется вfind
(x=10 find...
), который сам передает егоsh
.find: -readable: unknown primary or operator
,bash
.bash
это просто интерпретатор командной строки, ноfind
реализации.-readable
это расширение GNU, не доступен в OS / Xfind
. Он используется только для ограничения файлов, которые доступны для чтения (вы не сможете получить количество строк для нечитаемых файлов). Вы можете опустить его для первого, тогда вы просто получите сообщения об ошибках при открытии файлов дляwc
файлов, которые не читаются.Для полноты, кроме AWK, вы также можете использовать GNU sed для достижения того же результата:
Что приводит к более краткой командной строке.
объяснение
источник