Используя sed для редактирования любого из возникновения шаблона соответствия

Строка, запускающаяся с 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
6
задан 18 May 2018 в 00:24

5 ответов

Хотя Вы упомянули 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
7
ответ дан 23 November 2019 в 07:16

Это простое 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 - обменивайтесь пространством шаблона и держите пространство (активируйте строки, которые соответствуют строке, но не количеству),

Уровни отступа в объяснении указывают на уровни изогнутого вложения фигурной скобки.

Все другие строки проходят, не обрабатывая и печатаются.

5
ответ дан 23 November 2019 в 07:16

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

Объяснение:

позже могли бы Вы быть, должен был передать something представьте в виде строки как переменная, и Вы будете, должен был использовать что-то как edit=$somesting и используйте ENVIRON["edit"] там.

pattern="${patt//\\/\\\\}" edit="$something" awk '
    $0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 ENVIRON["edit"]};1' infile
5
ответ дан 23 November 2019 в 07:16

Вот способ выполнить в нем 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

4
ответ дан 23 November 2019 в 07:16

Другой вариант использования для 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.

2
ответ дан 23 November 2019 в 07:16

Другие вопросы по тегам:

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