Как заменить текст между двумя шаблонами на различных строках?

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

Только будет отдельное проявление запуска и закончит шаблон в каждом файле.

Мне нужен метод командной строки для замены текста между шаблонами, включая сами шаблоны. Вывод в новый файл или редактирование на месте прекрасны.

Команда, которая воздействует на единственный файл, будет работать, поскольку я могу циклично выполниться через файлы и применить команду сам. Я делал попытку a sed решению, но могло только удаться заменить все строки.

Пример текста был бы:

Cable Type ID:135, Installation ID:62, Alpha Conductor Origin:
Tolerance Report B74 - 3rd June 1996, Beta Conductor Origin: 
Tolerance Report B74 - 3rd June 1996, Phase Conductor Size: 
45mm, Security: Security-Start Bs86gKI-734Lw#32_nP/5589Zfb8Wj-
sW93j9b Security-End, Location ID:889, Protective Earth Size:
67mm, Protective Earth Max Current (A): 4, Overload Time...

Шаблон запуска Security-Start и шаблон конца Security-End. Я хочу заменить шаблоны и все промежуточное со словом REDACTED.

Я хотел бы, чтобы вывод был:

Cable Type ID:135, Installation ID:62, Alpha Conductor Origin:
Tolerance Report B74 - 3rd June 1996, Beta Conductor Origin: 
Tolerance Report B74 - 3rd June 1996, Phase Conductor Size: 
45mm, Security: REDACTED, Location ID:889, Protective Earth Size:
67mm, Protective Earth Max Current (A): 4, Overload Time...

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

Любой язык, который доступен по умолчанию в системе Ubuntu, будет прекрасен. Мои первые мысли являются 'sed' или 'awk', но независимо от того, что Вы довольны, будет прекрасен.

5
задан 18 May 2017 в 08:44

4 ответа

Это должно работать для вас:

sed -e '/Security-Start/{ N; s/Security-Start.*Security-End/REDACTED/ }'
  • /Security-Start/ поиск «Security-Start»
  • Если вы нашли его: «N;» означает добавить следующую строку.
  • и сделать замену s/Security-Start.*Security-End/REDACTED/ в конечном результате.

Для более чем двух строк используйте эту:

sed -n '1h; 1!H; ${ g; s/Security-Start.*Security-End/REDACTED/p }'

Прочитайте здесь

8
ответ дан 23 November 2019 в 08:39

Если файлы не слишком велики, вы можете использовать perl в режиме slurp :

$ perl -0777 -pe 's/Security-Start.*Security-End/REDACTED/s' file 
Cable Type ID:135, Installation ID:62, Alpha Conductor Origin:
Tolerance Report B74 - 3rd June 1996, Beta Conductor Origin: 
Tolerance Report B74 - 3rd June 1996, Phase Conductor Size: 
45mm, Security: REDACTED, Location ID:889, Protective Earth Size:
67mm, Protective Earth Max Current (A): 4, Overload Time...

Параметр командной строки -0777 эффективно удаляет разделитель записей, так что весь файл взломан. Модификатор s regex заставляет perl включать символы новой строки в ., что делает совпадение выражений между строками.


В качестве альтернативы, с циклом sed:

$ sed '/Security-Start/ {:a; $!N; s/Security-Start.*Security-End/REDACTED/; t; ba}' file
Cable Type ID:135, Installation ID:62, Alpha Conductor Origin:
Tolerance Report B74 - 3rd June 1996, Beta Conductor Origin: 
Tolerance Report B74 - 3rd June 1996, Phase Conductor Size: 
45mm, Security: REDACTED, Location ID:889, Protective Earth Size:
67mm, Protective Earth Max Current (A): 4, Overload Time...

С помощью GNU sed вы можете заменить t; ba (переход при успешной замене; (в противном случае) переход на :a) на [ 117] (переход к :a на и успешной замене).

8
ответ дан 23 November 2019 в 08:39

Более ручным подходом было бы заменить все символы новой строки во входном файле на NULL, использовать простое perl не жадное регулярное выражение, чтобы выполнить замену, а затем поместить символы новой строки обратно:

$ tr '\n' '\0' < file | 
    perl -pe 's/Security-Start.*?Security-End/Security: REDACTED/g' |
        tr '\0' '\n'
Cable Type ID:135, Installation ID:62, Alpha Conductor Origin:
Tolerance Report B74 - 3rd June 1996, Beta Conductor Origin: 
Tolerance Report B74 - 3rd June 1996, Phase Conductor Size: 
45mm, Security: Security: REDACTED, Location ID:889, Protective Earth Size:
67mm, Protective Earth Max Current (A): 4, Overload Time...
4
ответ дан 23 November 2019 в 08:39

Вот как вы можете сделать это с помощью awk:

awk -v RS='Security-Start.*Security-End' -v ORS= '1;NR==1{printf "REDACTED"}' file
1
ответ дан 23 November 2019 в 08:39

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

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