Я считаю, что ваш сценарий немного запутан и демонстрирует непонимание того, что такое awk. Программы Awk состоят из списка
pattern { actions }
заявление. Каждый раз, когда читается новая запись/строка, awk будет обрабатывать эту строку, выполняя оператор действия шаблона -один за другим. Из того, что я вижу, похоже, вы представляете, что awk считывает весь файл в памяти, а затем вы можете обработать его, используя цикл for по количеству записей. Это не так.
Следующий awk, вероятно, сделает то, что вы просите:
awk '/missing/' inputfile > "missing.txt"
Здесь шаблон — /missing/
, а действие — действие по умолчанию 1
, равное {print $0}
, или напечатать полную запись. Шаблон /missing/
гласит: выберите все строки, содержащие подстроку «отсутствует»
Во-первых, слово руководства. Этот «текст» на самом деле является языком разметки, таким как XML или аналогичный. Обработка таких сложных и нюансированных входных данных, как простой, несформированный текст, скорее всего, вызовет проблемы в долгосрочной перспективе. Я настоятельно рекомендую вместо этого использовать такой инструмент, как XMLStarlet или аналогичный.
При всем при этом одним из решений было бы использование переменных, как это предусмотрено (, например, )GNU awk:
awk -v target="$target" -v replacement="$replacement" '{ gsub(target, replacement, $0) } 1'
Я еще раз повторяю :, если вы собираетесь делать это неоднократно или без наблюдения за результатами, пожалуйста, избавьте себя от головной боли и используйте программу, которая на самом деле имеет дело со всеми тонкостями используемого вами языка разметки, например. XMLStarlet , Python lxml
или аналогичные.
Вы упускаете из виду основной принцип работы sed
. Это линейно-ориентированный редактор, поскольку он извлекает ввод построчно. В то время как вы просите его обработать многострочное регулярное выражение, которое, очевидно, никогда не совпадет.
Если у вас есть GNU sed
, вы можете slurp
вставить файл с помощью опции -z
в sed. Он смотрит на разделитель записей NUL=\0
, которого нет в текстовых файлах. Следовательно, он будет читать весь файл как одну длинную запись.
Нам нужно настроить целевые и замещающие переменные, поскольку они предположительно могут содержать символы, которые sed обрабатывает как регулярное выражение. Поэтому нам нужно экранировать их и только потом использовать в выражении sed.
srch=$(printf '%s\n' "$target" |
sed -e '
H;1h;$!d;x
s:[][\/^$*.]:\\&:g
s/[[:space:]]\{1,\}/[[:space:]]\\{1,\\}/g
')
repl=$(printf '%s\n' "$replacement" |
sed -e '
s:[\&/]:\\&:g
$!s:$:\\:
')
sed -e '$!{' -e 'N;H;s/.*//;x;D' -e '}' -e "s/$srch/$repl/g" file.txt
Результаты:
<a>
<b>
<c>
R-HELLO-1
</c>
</b>
</a>
<html>
<head>
<title>
O-HELLO-2
</title>
</head>
</html>
в случае, если в вашей системе установлен perl
, вы также можете использовать это; мы сопоставляем один и тот же скелет, но разное количество пробелов, потому что вы не хотите, чтобы один пробел испортил совпадение.
srch="$target" \
repl="$replacement" \
perl -0777 -pe '
(my $re = quotemeta $ENV{srch}) =~ s/(\\\s)+/\\s+/g;
s/$re/$ENV{repl}/g;
' file.txt