Как я могу заменить все в строке с помощью 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.