Количество элементов в каталоге можно подсчитать, используя
set -- *
Это устанавливает позиционные параметры ($1
, $2
и т. д. )на имена в текущем каталоге. Количество имен, до которых расширяется *
, находится в $#
. Если вы используете оболочку bash
и устанавливаете опцию оболочки dotglob
, это дополнительно будет учитывать скрытые имена.
Использование для поиска каталогов в /grid/sdh/hadoop/yarn/local/usercache/hdfs/appcache
, которые содержат более 1000 имен:
find /grid/sdh/hadoop/yarn/local/usercache/hdfs/appcache \
-type d -exec bash -O dotglob -c '
for pathname do
set -- "$pathname"/*
if [ "$#" -gt 1000 ]; then
printf "%d\t%s\n" "$#" "$pathname"
fi
done' bash {} +
Это расширяет глобус оболочки *
в каждом найденном каталоге и выводит путь к каталогу, если в нем более 1000 имен, вместе с количеством имен. Он делает это, выполняя короткий сценарий bash
для пакетов каталогов. Сценарий будет перебирать каждую группу каталогов и для каждого из них будет расширять глобус *
внутри него, чтобы подсчитать количество записей. Оператор if
затем запускает printf
, если это необходимо.
Учтите, что если каталог содержит миллионы имен, может потребоваться некоторое время, чтобы развернуть *
глобус в этом каталоге.
Простой способ сохранить только последнюю совпадающую строку состоит в том, чтобы напечатать ввод в обратном порядке, выбрать только первую совпадающую строку, а затем напечатать вывод в обратном порядке в конвейере. Предполагая, что tac
из GNU Coreutils доступен вам:
tac input_file | awk '!/test$/ || !seen++' | tac >output_file
В -редактирование места (, как вы просили в комментарии ), обычно получается путем переноса команд в скрипт или функцию, которая заботится о перезаписи файла (с )задан как аргумент (s )с обработанным выводом.
tmpdir=$(mktemp -d)
cp input_file "$tmpdir/file"
tac "$tmpdir/file" | awk '!/test$/ || !seen++' | tac >input_file
rm -r "$tmpdir"
Если ваша оболочка поддерживает опцию pipefail
(Я могу успешно протестировать bash, ksh93, mksh, zsh, используя setopt PIPE_FAIL
, busybox ash, yash ), это можно сделать более безопасным с помощью set -e
иset -o pipefail
:ошибки (, в том числе возникающие где-либо в конвейере ), приведут к остановке выполнения до того, как временный файл будет удален.
На поддерживающих его платформах, при условии, что вас не волнует потеря данных в случае, если что-то пойдет не так, вы также можете использовать:
{ rm file; tac | awk '!/test$/ || !seen++' | tac >file; } <file
Обратите внимание, что это изменит индексный дескриптор file
(, как и параметр редактирования in -, предоставляемый многими распространенными инструментами ).
Если вместо этого вы хотите удалить первые n совпадающие строки, предполагая здесь n = 2:
awk '!/test$/ || ++seen > 2' input_file >output_file
В этом случае, в -редактирование места удобно разрешено возможностью GNU awk
импортировать дополнительные библиотеки (и, в частности, "на месте", поставляемую с самим gawk
):
awk -i inplace '...' file
Подробнее об этом можно узнать в этом другом ответе на U&L.
По поводу опции -"Удаление первых N строк совпадений с образцом"
На sed
можно организовать счетчик в трюме (дополнительный буфер ).
sed -r '/test$/!b;x;s/$/-/;/-{4}/!{x;d};x' file
/test$/!b
-Безусловный переход в конец при отсутствии сопоставления с образцом. x
-Поменять местами содержимое паттерна и пробелов. s/$/-/
-Для каждого совпадения добавьте один символ в конец счетчика, в моем случае дефис. /-{4}/!{x;d}
-Если счетчик содержит менее 4 символов, то удалить строку в пространстве шаблона.