Как выполнить sed -e 's///' для всего, кроме определенного шаблона?

Как выполнить sed -e 's///' для всего, кроме определенного шаблона?

Как я могу заменить все в строке с помощью sed, кроме % и любого числа, непосредственно следующего за ним? То есть, все, кроме строк, таких как:

%1 %1000 %55 и т. д.

Даны строки такой формы:

    1: [18x14] [history 1/2000, 268 bytes] %3
    2: [18x14] [history 1/2000, 268 bytes] %4 (active)

Я хочу получить только части %3и %4. Цифры могут доходить до 999.

решение1

$ sed 's/^.*\(%[0-9]\+\).*$/\1/' input

Предположим, что строка содержит не более одного такого %123токена и что каждая строка содержит такой токен.

Метасимвол \( \)отмечает группу соответствия, на которую затем ссылаются при замене через \1обратную ссылку. ^/ $соответствует началу/концу строки.

В противном случае вы можете предварительно отфильтровать входные данные, например:

$ grep '%[0-9]\+' input | sed 's/^.*\(%[0-9]\+\).*$/\1/'

(когда не все строки содержат такой токен)

Другой вариант:

$ sed 's/\(%[0-9]\+\)/\n\1\n/g' | grep '%[0-9]'

(когда строка может содержать несколько таких токенов)

Вот разрывы строк, вставленные непосредственно перед и после каждого токена - в первой части конвейера. Затем часть grepудаляет все %123нетокеновые строки.

решение2

grep -oВ этом случае вам, возможно, лучше использовать :

grep -oP '\B%[0-9]{1,3}\b' inputfile

Предполагая, что ваша версия grepподдерживает регулярные выражения, совместимые с Perl ( -P). В противном случае:

grep -o '\B%[0-9]\{1,3\}\b' inputfile

Используя GNU sed, можно транслитерировать пробелы в символы новой строки и получить нужные строки:

sed 'y/ /\n/' inputfile | sed '/^%[0-9]\{1,\}/!d'

решение3

При работе с sedпочти всегда целесообразно:

/address then/s/earch/replace/

На это есть две причины. Первая заключается в том, что с несколькими строками /addressing/это быстрее - это оптимизировано только длянаходитьсовпадение и не утруждает себя выбором только частей строки для редактирования, что позволяет быстрее сузить результаты.

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

Конечно, в этом случае, учитывая только те данные, которые вы показываете, это не имеет практического значения. Тем не менее, вот как я бы сделал то, о чем вы спрашиваете:

sed '/^[^%]*\|[^0-9]*$/s///g' <<\DATA
    1: [18x14] [history 1/2000, 268 bytes] %3
    2: [18x14] [history 1/2000, 268 bytes] %4 (active)
DATA

#OUTPUT
%3
%4

Он просто выбирает все символы, которыене-%символы из начала строки и всенечисловойсимволы с конца строки в адресе, а затем удаляет их с помощью s///- и всё.

В своем нынешнем виде он может искажать данные неожиданным образом, если вы вводите в него строки.нетсодержащий %digitкомбо - и вот почему адресация важна. Если мы немного изменим его:

/%[0-9]/s/[^%]*\|[^0-9]*$//g

Становится безопаснееиБыстрее.

решение4

В моем решении используется не sed, а grep с расширенными регулярными выражениями и опциями только сопоставления.


$ cat file
1: [18x14] [history 1/2000, 268 bytes] %3
2: [18x14] [history 1/2000, 268 bytes] %4 (active)
$ cat file | grep -Eo '%[0-9]+'
%3
%4

Использовать grep в этом случае проще, чем sed.

Связанный контент