Удаление первых N строк, соответствующих шаблону, с сохранением последней

Количество элементов в каталоге можно подсчитать, используя

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, если это необходимо.

Учтите, что если каталог содержит миллионы имен, может потребоваться некоторое время, чтобы развернуть *глобус в этом каталоге.

1
13.10.2020, 15:32
2 ответа

Простой способ сохранить только последнюю совпадающую строку состоит в том, чтобы напечатать ввод в обратном порядке, выбрать только первую совпадающую строку, а затем напечатать вывод в обратном порядке в конвейере. Предполагая, что 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.

3
18.03.2021, 22:57

По поводу опции -"Удаление первых N строк совпадений с образцом"
На sedможно организовать счетчик в трюме (дополнительный буфер ).

sed -r '/test$/!b;x;s/$/-/;/-{4}/!{x;d};x' file

/test$/!b-Безусловный переход в конец при отсутствии сопоставления с образцом.
x-Поменять местами содержимое паттерна и пробелов.
s/$/-/-Для каждого совпадения добавьте один символ в конец счетчика, в моем случае дефис.
/-{4}/!{x;d}-Если счетчик содержит менее 4 символов, то удалить строку в пространстве шаблона.

0
18.03.2021, 22:57

Теги

Похожие вопросы