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

Самое лучшее, что нужно сделать, это резервное копирование ваших файлов на внешний жесткий диск. Это самый лучший способ убедиться, что во время процесса ничего не получится с вашими файлами.

Простой способ: если вы создадите резервную копию всех ваших файлов на внешнем жестком диске, самым простым способом будет «заменить Windows» Ubuntu "

Трудный способ сохранить оба раздела: Для вашей конфигурации вам нужно будет подумать о том, что администратор раздела вручную (на« что-то еще », если моя догадка правильная, как чего вы видите). Затем на вашем основном разделе (том, который будет иметь тот же размер, что и ваш диск с Windows «C» (Linux не распознает диски как «C» или «D»), щелкните правой кнопкой мыши и выберите «формат». Выберите «ext4» в качестве файловой системы и «/» в качестве точки монтирования. Выберите «/ dev / sda» в качестве точки захвата. Затем проверьте.

6
задан 18 May 2018 в 10:24

20 ответов

Хотя вы упоминали 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 - это идиома; поскольку это правда, все записи будут напечатаны

Пример:

% 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
ответ дан 22 May 2018 в 10:38
  • 1
    Я думаю, что более подходящее прилагательное, чем «awk -y» будет "awk -ward". ; -] – David Foerster 17 May 2018 в 16:10

Хотя вы упоминали 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 - это идиома; поскольку это правда, все записи будут напечатаны

Пример:

% 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
ответ дан 17 July 2018 в 14:04

Хотя вы упоминали 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 - это идиома; поскольку это правда, все записи будут напечатаны

Пример:

% 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
ответ дан 20 July 2018 в 14:08

Хотя вы упоминали 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 - это идиома; поскольку это правда, все записи будут напечатаны

Пример:

% 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 July 2018 в 09:39

Эта простая команда sed позволяет выборочно производить изменение без использования циклов (он использует ветку от конца) или требует расширения GNU или сразу считывает весь файл:

sed -r '/Fred Flintstone/ {x; s/$/#/; /^#{2}$/ {x; s/.*/& someString/; b}; x}'
1] Объяснение:

-r - использовать расширенное регулярное выражение /Fred Flintstone/ - для строк, соответствующих этому шаблону: x - обменивать пространство и пространство удержания (активировать счетчик) s/$/#/ - добавить символ в счетчик /^#{2}$/ - когда счетчик равен 2 (замените любое значение) x обменивайте пространство шаблона и удерживайте пробел (активируйте подсчитанную строку ввода) s/.*/& someString/ - добавьте строку в нужную строку b - пропустить до конца обработки для этой строки, чтобы ее можно было напечатать x - обменять пространство шаблона и удерживать пространство (активировать строки, соответствующие строке, но не счету)

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

Все остальные строки проходят без обработки и печатаются.

5
ответ дан 22 May 2018 в 10:38
  • 1
    это путь sed – Matija Nalis 18 May 2018 в 03:02
  • 2
    Хорошо работает со всеми различными событиями! Спасибо за объяснение. Хорошего дня – DazzlerJay 18 May 2018 в 10:14
  • 3
    +1 Я добавил это в закладки. – Scott 20 May 2018 в 08:34
awk '/Fred Flintstone/&& ++seen==2{ $0=$0"someString" };1 ' infile

Это будет печатать каждую строку awk reads (1, которая всегда является истинным условием, приведет к тому, что каждая строка awk будет прочитана / продолжена) и увеличьте значение переменной seen, когда строка, соответствующая [ f4], и как только вторая строка будет соответствовать Fred Flintstone (теперь seen==2), она будет печатать эту строку с добавленным "someString" в конце.

5
ответ дан 22 May 2018 в 10:38
  • 1
    (Нумерация продолжалась с предыдущих комментариев, которые были удалены.) – Scott 21 May 2018 в 23:54
  • 2
    (3) Слишком плохо, что вы не понимали, что ваша команда sed может быть исправлена ​​просто путем изменения s/Fred Flintstone/& someString/2 на s/Fred Flintstone[^\n]*/& someString/2. (4) Да, это правда, что ответ heemayl использует if, а ваш нет. Есть некоторые преимущества малости, но, поскольку не все понимают разницу между count++ и ++count, я не верю, что ваша команда более ясна, чем его. (5) Вы сказали, что «он бесполезно использует awk-переменную там , а также $0 ~ var ...» (выделено мной). (5a) Присвоение строки поиска переменной awk ... (Продолжение) – Scott 21 May 2018 в 23:54
  • 3
    (Cont'd) ... позволяет указать его как параметр сценария с меньшим риском инъекции кода, чем если бы вы сказали "/$1/ && ++seen==2 …". (5b) Присвоение строки поиска переменной awk и использование $0 ~ var позволяет вам включить / в строку поиска, не беспокоясь об экранировании с помощью обратного слэша, и позволяет включить ' [!d0 ] (одиночная кавычка) в строке поиска, не беспокоясь о сложении цитирования строки awk-программы. (5c) После того, как вы назначили строку поиска переменной awk, тогда $0 ~ var - единственный способ поиска строк, содержащих ее. – Scott 21 May 2018 в 23:54
  • 4
    (Продолжение) ... P.S. Ваше объяснение не очень читаемо. "Всегда Условие True приведет к печати каждой строки awk читается / продолжается" выглядит как копия & amp; вставить ошибку (или ваша кошка типа это? :-)). – Scott 21 May 2018 в 23:54

Вот способ сделать это в 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

Hmm. .. подумав об этом еще немного, он фактически добавит новый текст в любое другое событие - не только второе. Если вам действительно нужно использовать замену только второго вхождения, то единственным способом, который я могу это сделать, будет:

найти первое вхождение шаблона и изменить новый первый экземпляр добавляет следующую строку N в пространство шаблона

GNU sed предоставляет трюк, чтобы обратиться к Хм ... после размышления об этом более того, он фактически добавит новый текст к любому другому вхождению - не только второй экземпляр шаблона

0,/pattern/

So

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

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

или как однострочный 22]

printf '1;#\n/Fred Flintstone/,/Fred Flintstone/ s//& someString/\n,p\n' | ed -s File1

Вы можете сделать версию ed на месте, заменив ,p на w

4
ответ дан 22 May 2018 в 10:38
  • 1
    Вышеупомянутый ответ хорошо работает со всеми различными событиями, но с первым. Я хочу иметь свободу изменения конкретного события (скажите сначала, второе или третье) – DazzlerJay 17 May 2018 в 15:42
  • 2
    (1) В вашем ed решении /Fred Flintstone/,/Fred Flintstone/ не является необходимым и запутанным - /Fred Flintstone/s//& someString/ будет достаточно. (2) За исключением, вместо s//& someString/, вы должны сказать s/$/ someString/, как предлагалось. (Вопрос непонятен, и образец файла неаккуратен и не очень иллюстративен. Но в вопросе последовательно говорится, что строка «должна быть добавлена ​​с некоторой строкой». Основываясь на описании проблемы, строка, содержащая «FredFlintstone и Wilma "следует заменить на" FredFlintstone andWilma someString ", ... (Продолжение) – Scott 20 May 2018 в 08:31
  • 3
    (Cont'd) ... тогда как ваш ответ изменит его на «FredFlintstone someString andWilma».) (3) Это зависит от первой строки файла, содержащего «FredFlintstone». Если это не так, тогда ваш ответ изменит первое вхождение. (4) Было бы неплохо, если бы вы объяснили, как получить доступ к третьей, четвертой или пятой строке, содержащей «FredFlintstone» - или первый. ( Я знаю, как это сделать, дайте мне знать, если вам нужна помощь.) ... ... ... ... ... ... ... ... ... Pleasedonot ответить в комментариях; отредактируйте ваш ответ, сделайте его более ясным и более полным. – Scott 20 May 2018 в 08:31

Другой вариант использования для ex, указанного в файле POSIX редактора файлов

(Это предшественник vi и все еще является частью vi.)

printf '%s\n' '0/Fred Flintstone///s/$/ someString/' x | ex filename
3] Магия здесь заключается в том, что в отличие от Sed, Awk и подобных инструментов, ex не запускает код на каждой строке. Вы можете перемещать курсор вокруг, давать команды и т. Д.

В этом случае мы укажем номер строки 0 (что гарантирует, что Фред Флинтстон на первой строке будет учтен), а затем регулярное выражение /Fred Flintstone/, которое ссылается на первую строку в файле, соответствующем этому регулярному выражению, за которым следует другое регулярное выражение //, которое, будучи пустым, повторно использует последнее регулярное выражение и поэтому ссылается на вторую строку в файле, который соответствует; а затем мы используем команду s, которую вы уже знаете.

Команда x означает сохранение любых изменений и выход.

Мы используем printf для подачи команд на ex.

2
ответ дан 22 May 2018 в 10:38
  • 1
    Это было бы лучшим ответом, если бы вы объяснили, как получить доступ к третьей, четвертой или пятой строке, содержащей «FredFlintstone» - или первый. ( Я знаю, как это сделать, но я уверен, что 98% пользователей не смогут понять это.) Ihope Idon't havetotellyou: happyonot ответить Комментарии; отредактируйте ваш ответ, сделайте его более ясным и более полным. – Scott 20 May 2018 в 08:35

Эта простая команда sed позволяет выборочно производить изменение без использования циклов (он использует ветку от конца) или требует расширения GNU или сразу считывает весь файл:

sed -r '/Fred Flintstone/ {x; s/$/#/; /^#{2}$/ {x; s/.*/& someString/; b}; x}'

Объяснение:

-r - использовать расширенное регулярное выражение /Fred Flintstone/ - для строк, соответствующих этому шаблону: x - обменивать пространство и пространство удержания (активировать счетчик) s/$/#/ - добавить символ в счетчик /^#{2}$/ - когда счетчик равен 2 (замените любое значение) x обменивайте пространство шаблона и удерживайте пробел (активируйте подсчитанную строку ввода) s/.*/& someString/ - добавьте строку в нужную строку b - пропустить до конца обработки для этой строки, чтобы ее можно было напечатать x - обменять пространство шаблона и удерживать пространство (активировать строки, соответствующие строке, но не счету)

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

Все остальные строки проходят без обработки и печатаются.

5
ответ дан 17 July 2018 в 14:04

Вот способ сделать это в 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

Hmm. .. подумав об этом еще немного, он фактически добавит новый текст в любое другое событие - не только второе. Если вам действительно нужно использовать замену только второго вхождения, то единственным способом, который я могу это сделать, будет:

найти первое вхождение шаблона и изменить новый первый экземпляр добавляет следующую строку N в пространство шаблона

GNU sed дает трюк, чтобы обратиться к Хм ... после размышления об этом более того, он фактически добавит новый текст к любому другому вхождению - не только второй экземпляр шаблона

0,/pattern/

So

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

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

Вы можете сделать версию ed на месте, заменив ,p на w

4
ответ дан 17 July 2018 в 14:04

Другой вариант использования для ex, указанного в файле POSIX редактора файлов

(Это предшественник vi и все еще является частью vi.)

printf '%s\n' '0/Fred Flintstone///s/$/ someString/' x | ex filename

Магия здесь заключается в том, что в отличие от Sed, Awk и подобных инструментов, ex не запускает код на каждой строке. Вы можете перемещать курсор вокруг, давать команды и т. Д.

В этом случае мы укажем номер строки 0 (что гарантирует, что Фред Флинтстон на первой строке будет учтен), а затем регулярное выражение /Fred Flintstone/, которое ссылается на первую строку в файле, соответствующем этому регулярному выражению, за которым следует другое регулярное выражение //, которое, будучи пустым, повторно использует последнее регулярное выражение и поэтому ссылается на вторую строку в файле, который соответствует; а затем мы используем команду s, которую вы уже знаете.

Команда x означает сохранение любых изменений и выход.

Мы используем printf для подачи команд на ex.

2
ответ дан 17 July 2018 в 14:04

Пересмотренный ответ, чтобы предотвратить впрыскивание кода в обратную косую черту, а также косые черты, кавычки при использовании awk-переменных awk -v variable ... или оболочки awk '...' variable="$value", поскольку awk выполняет обработку последовательности вызовов C на значениях, переданных с помощью -v variable= или оболочки variable=$value; поэтому оболочка variable='\\n' изменится на \n в awk).

pattern="${patt//\\/\\\\}" awk ' $0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 "something"};1' infile

для нижнего входа и awk :

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//\\/\\\\}" ускользает назад -Slashes в переменной $patt, потому что ["the '~' operator does pattern matching, treating the right hand operand as an (extended) regular expression, and the left hand one as a string" by muru], тогда вам нужно будет избежать всех символов, которые являются особыми в ERE. Это $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
5
ответ дан 17 July 2018 в 14:04

Эта простая команда sed позволяет выборочно производить изменение без использования циклов (он использует ветку от конца) или требует расширения GNU или сразу считывает весь файл:

sed -r '/Fred Flintstone/ {x; s/$/#/; /^#{2}$/ {x; s/.*/& someString/; b}; x}'

Объяснение:

-r - использовать расширенное регулярное выражение /Fred Flintstone/ - для строк, соответствующих этому шаблону: x - обменивать пространство и пространство удержания (активировать счетчик) s/$/#/ - добавить символ в счетчик /^#{2}$/ - когда счетчик равен 2 (замените любое значение) x обменивайте пространство шаблона и удерживайте пробел (активируйте подсчитанную строку ввода) s/.*/& someString/ - добавьте строку в нужную строку b - пропустить до конца обработки для этой строки, чтобы ее можно было напечатать x - обменять пространство шаблона и удерживать пространство (активировать строки, соответствующие строке, но не счету)

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

Все остальные строки проходят без обработки и печатаются.

5
ответ дан 20 July 2018 в 14:08

Вот способ сделать это в 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

Hmm. .. подумав об этом еще немного, он фактически добавит новый текст в любое другое событие - не только второе. Если вам действительно нужно использовать замену только второго вхождения, то единственным способом, который я могу это сделать, будет:

найти первое вхождение шаблона и изменить новый первый экземпляр добавляет следующую строку N в пространство шаблона

GNU sed дает трюк, чтобы обратиться к Хм ... после размышления об этом более того, он фактически добавит новый текст к любому другому вхождению - не только второй экземпляр шаблона

0,/pattern/

So

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

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

Вы можете сделать версию ed на месте, заменив ,p на w

4
ответ дан 20 July 2018 в 14:08

Другой вариант использования для ex, указанного в файле POSIX редактора файлов

(Это предшественник vi и все еще является частью vi.)

printf '%s\n' '0/Fred Flintstone///s/$/ someString/' x | ex filename

Магия здесь заключается в том, что в отличие от Sed, Awk и подобных инструментов, ex не запускает код на каждой строке. Вы можете перемещать курсор вокруг, давать команды и т. Д.

В этом случае мы укажем номер строки 0 (что гарантирует, что Фред Флинтстон на первой строке будет учтен), а затем регулярное выражение /Fred Flintstone/, которое ссылается на первую строку в файле, соответствующем этому регулярному выражению, за которым следует другое регулярное выражение //, которое, будучи пустым, повторно использует последнее регулярное выражение и поэтому ссылается на вторую строку в файле, который соответствует; а затем мы используем команду s, которую вы уже знаете.

Команда x означает сохранение любых изменений и выход.

Мы используем printf для подачи команд на ex.

2
ответ дан 20 July 2018 в 14:08

Пересмотренный ответ, чтобы предотвратить впрыскивание кода в обратную косую черту, а также косые черты, кавычки при использовании awk-переменных awk -v variable ... или оболочки awk '...' variable="$value", поскольку awk выполняет обработку последовательности вызовов C на значениях, переданных с помощью -v variable= или оболочки variable=$value; поэтому оболочка variable='\\n' изменится на \n в awk).

pattern="${patt//\\/\\\\}" awk ' $0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 "something"};1' infile

для нижнего входа и awk :

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//\\/\\\\}" ускользает назад -Slashes в переменной $patt, потому что ["the '~' operator does pattern matching, treating the right hand operand as an (extended) regular expression, and the left hand one as a string" by muru], тогда вам нужно будет избежать всех символов, которые являются особыми в ERE. Это $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
5
ответ дан 20 July 2018 в 14:08

Эта простая команда sed позволяет выборочно производить изменение без использования циклов (он использует ветку от конца) или требует расширения GNU или сразу считывает весь файл:

sed -r '/Fred Flintstone/ {x; s/$/#/; /^#{2}$/ {x; s/.*/& someString/; b}; x}'

Объяснение:

-r - использовать расширенное регулярное выражение /Fred Flintstone/ - для строк, соответствующих этому шаблону: x - обменивать пространство и пространство удержания (активировать счетчик) s/$/#/ - добавить символ в счетчик /^#{2}$/ - когда счетчик равен 2 (замените любое значение) x обменивайте пространство шаблона и удерживайте пробел (активируйте подсчитанную строку ввода) s/.*/& someString/ - добавьте строку в нужную строку b - пропустить до конца обработки для этой строки, чтобы ее можно было напечатать x - обменять пространство шаблона и удерживать пространство (активировать строки, соответствующие строке, но не счету)

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

Все остальные строки проходят без обработки и печатаются.

5
ответ дан 23 July 2018 в 09:39

Вот способ сделать это в 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

Hmm. .. подумав об этом еще немного, он фактически добавит новый текст в любое другое событие - не только второе. Если вам действительно нужно использовать замену только второго вхождения, то единственным способом, который я могу это сделать, будет:

найти первое вхождение шаблона и изменить новый первый экземпляр добавляет следующую строку N в пространство шаблона

GNU sed предоставляет трюк, чтобы обратиться к Хм ... после размышления об этом более того, он фактически добавит новый текст к любому другому вхождению - не только второй экземпляр шаблона

0,/pattern/

So

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

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

Вы можете сделать версию ed на месте, заменив ,p на w

4
ответ дан 23 July 2018 в 09:39

Другой вариант использования для ex, указанного в файле POSIX редактора файлов

(Это предшественник vi и все еще является частью vi.)

printf '%s\n' '0/Fred Flintstone///s/$/ someString/' x | ex filename

Магия здесь заключается в том, что в отличие от Sed, Awk и подобных инструментов, ex не запускает код на каждой строке. Вы можете перемещать курсор вокруг, давать команды и т. Д.

В этом случае мы укажем номер строки 0 (что гарантирует, что Фред Флинтстон на первой строке будет учтен), а затем регулярное выражение /Fred Flintstone/, которое ссылается на первую строку в файле, соответствующем этому регулярному выражению, за которым следует другое регулярное выражение //, которое, будучи пустым, повторно использует последнее регулярное выражение и поэтому ссылается на вторую строку в файле, который соответствует; а затем мы используем команду s, которую вы уже знаете.

Команда x означает сохранение любых изменений и выход.

Мы используем printf для подачи команд на ex.

2
ответ дан 23 July 2018 в 09:39

Пересмотренный ответ, чтобы предотвратить впрыскивание кода в обратную косую черту, а также косые черты, кавычки при использовании awk-переменных awk -v variable ... или оболочки awk '...' variable="$value", поскольку awk выполняет обработку последовательности вызовов C на значениях, переданных с помощью -v variable= или оболочки variable=$value; поэтому оболочка variable='\\n' изменится на \n в awk).

pattern="${patt//\\/\\\\}" awk ' $0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 "something"};1' infile

для нижнего входа и awk :

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//\\/\\\\}" ускользает назад -Slashes в переменной $patt, потому что ["the '~' operator does pattern matching, treating the right hand operand as an (extended) regular expression, and the left hand one as a string" by muru], тогда вам нужно будет избежать всех символов, которые являются особыми в ERE. Это $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
5
ответ дан 23 July 2018 в 09:39

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

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