Строка, запускающаяся с Fred Flintstone, должна быть добавлена с некоторой строкой. Ищут указанное возникновение Fred Flintstone и добавляют его.
Как я использую эту команду для кого-либо из случаев такого шаблона? Я попробовал
sed '/Fred Flintstone/ s/$/ someString/2' filename
По-видимому, выше каждый не работает. Это работает хорошо на все случаи, но не определенное возникновение. (Скажите, что я хочу заменить сначала или второй или третий [любой из них]),
Пример File1:
Fred Flintstone
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark
Желаемый вывод File1:
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
Хотя Вы упомянули sed
, это вид awk
- y задачи:
awk -v pat="Fred Flintstone" '$0 ~ pat {count++;\
if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
-v pat="Fred Flintstone"
сохраняет шаблон Regex для соответствия как переменная pat
использоваться внутри awk
выражения
$0 ~ pat
проверяет запись по pat
для соответствия; если подобрано, count
переменная увеличена на 1 и если count
2, запись сбрасывается как наличие текущего содержания плюс someString
({count++; if (count == 2) { $0 = $0" someString" ;} ;}
)
1 идиома; поскольку это - truthy, все записи были бы распечатаны
Пример:
% cat file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark
% awk -v pat="Fred Flintstone" '$0 ~ pat {count++; if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
Это простое sed
команда позволяет Вам выборочно вносить изменение, не используя циклы (это действительно использует ответвление к концу), или необходимость расширения GNU или чтение целого файла сразу:
sed -r '/Fred Flintstone/ {x; s/$/#/; /^#{2}$/ {x; s/.*/& someString/; b}; x}'
Объяснение:
-r
- используйте расширенный regex/Fred Flintstone/
- для строк, которые соответствуют этому шаблону: x
- обменное пространство шаблона и содержит пространство (активируйте счетчик),s/$/#/
- добавьте символ к счетчику/^#{2}$/
- когда счетчик будет длиной 2 (замените любым значением), x
обменивайтесь пространством шаблона и держите пространство (активируйте считаемую входную строку),s/.*/& someString/
- добавьте строку к желаемой строкеb
- пропустите в конец обработки для этой строки, таким образом, она может быть распечатанаx
- обменивайтесь пространством шаблона и держите пространство (активируйте строки, которые соответствуют строке, но не количеству),Уровни отступа в объяснении указывают на уровни изогнутого вложения фигурной скобки.
Все другие строки проходят, не обрабатывая и печатаются.
Пересмотренный ответ для предотвращения инжекции кода на обратных косых чертах, а также наклонных чертах, кавычках при использовании awk переменных awk -v variable ...
или оболочка awk '...' variable="$value"
так как awk делает обработку escape-последовательности C на значениях, переданных с -v variable=
или оболочка variable=$value
; так оболочка variable='\\n'
изменится на \n
в awk).
pattern="${patt//\\/\\\\}" awk '
$0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 "something"};1' infile
для ниже входа и шаблона:
another break line
Johnson Stone
\"Fred //\\Flintstone' SOMETHING will goes here ...
\"Fred //\\Flintstone'
Michael Clark
шаблон находится в названной переменной patt
$ echo "$patt"
\"Fred //\\Flintstone'
Вывод:
\"Fred //\\Flintstone'
another break line
Johnson Stone
\"Fred //\\Flintstone' SOMETHING will goes here ...something
\"Fred //\\Flintstone'
Michael Clark
Это pattern="${patt//\\/\\\\}"
Escape все обратные косые черты в $patt
переменная, потому что ["the '~' operator does pattern matching, treating the right hand operand as an (extended) regular expression, and the left hand one as a string
"muru], необходимо будет выйти из всех символов, которые специальны в EREs затем.
Это $0 ~ ENVIRON["pattern"]{ seen++ }
проверки, если текущая строка соответствовала pattern
, затем увеличьте ценность seen++
однажды.
Это seen==2 { $0 = $0 "something"}'
проверки, если была вторая строка, соответствовавшая pattern
в вышеупомянутом результате (теперь seen==2
), затем добавьте строку "somestring" в конце той строки.
1
(или любой оператор True) в конце включает awk печать по умолчанию.
позже могли бы Вы быть, должен был передать something
представьте в виде строки как переменная, и Вы будете, должен был использовать что-то как edit=$somesting
и используйте ENVIRON["edit"]
там.
pattern="${patt//\\/\\\\}" edit="$something" awk '
$0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 ENVIRON["edit"]};1' infile
Вот способ выполнить в нем sed
не хлебая целый файл в память:
N
к пространству шаблонаTa
$q
выходит из цикла, если конец файла достигнут без соответствия.
Так
sed '/Fred Flintstone/ {:a; $q; N; s//& someString/2; Ta;}' File1
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
Хотя T
расширение GNU, можно сделать то же в POSIX sed
использование t; ba
Хм... после размышления об этом еще немного, это на самом деле добавит новый текст к любому возникновению - не только второе. Если действительно необходимо использовать замену только второе возникновение, то единственный способ, которым я могу думать, чтобы сделать это, был бы:
GNU sed
обеспечивает прием для обращения к первой инстанции шаблона
0,/pattern/
Так
sed -e '0,/Fred Flintstone/ s//Barney Rubble/' \
-e '0,/Fred Flintstone/ s//& someString/' \
-e '0,/Barney Rubble/ s//Fred Flintstone/
' File1
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
Если Вы не возражаете использовать редактора, то можно обратиться к второму экземпляру более непосредственно путем движения в первую строку и затем соответствия вперед от одного экземпляра до следующего:
ed -s File1 << \EOF
1;#
/Fred Flintstone/,/Fred Flintstone/ s//& someString/
,p
q
EOF
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
или как острота
printf '1;#\n/Fred Flintstone/,/Fred Flintstone/ s//& someString/\n,p\n' | ed -s File1
Можно сделать версию редактора оперативной путем замены ,p
с w
ex
, указанный POSIX редактор файлов(Это - предшественник vi
и все еще часть vi
.)
printf '%s\n' '0/Fred Flintstone///s/$/ someString/' x | ex filename
Волшебство здесь состоит в том что в отличие от Sed, Awk и подобных инструментов, ex
не выполняет код каждой строки. Можно переместить курсор, дать команды и т.д.
В этом случае мы даем номер строки 0
(который гарантирует, что Fred Flintstone на первой строке будет принят во внимание), сопровождаемый regex /Fred Flintstone/
который отсылает первую строку в файле, соответствующем этому regex, сопровождаемый другим regex //
который, будучи пустым, снова использует последний regex и так относится к второй строке в файле, который соответствует; и затем мы используем s
команда, которую Вы уже знаете.
x
управляйте средствами сохранить любые изменения и выход.
Мы используем printf
подавать команды к ex
.