Я использую Awk для поиска ключевого слова <replaceme>
и замены его строкой. Эта строка содержит символы «\n», но Awk интерпретирует ее как новую строку. Я очень хочу сохранить обоих символов: \
и n
.
У меня есть строка, содержащая настоящую новую строку, и мне нужно заменить ее символами «\n». Оно работает:
mytext=$'hello\nhow are you'
mytext2=${mytext//$'\n'/\\n}
echo "$mytext"
hello
how are you
echo "$mytext2"
hello\nhow are you
Тогда у меня есть ключевое слово <replaceme>
в тексте, и я хотел бы заменить его содержанием $mytext2
.
echo 'this is the text: <replaceme>' |
awk -v srch = "<replaceme>" -v repl = "$mytext2" '{
gsub(srch,repl,$0); print $0 }'
Я получаю этот результат.
this is the text: hello
how are you
Но мне бы хотелось:
this is the text: hello\nhow are you
Подскажите, пожалуйста, как действовать?
Примечание: на самом деле текст «это текст:» находится в файле, и я использую cat myfile.txt | ок...
🤔 А знаете ли вы, что...
С помощью Bash можно создавать и запускать скрипты для автоматизации повседневных задач.
Вы можете использовать это awk
решение:
mytext=$'hello\nhow are you'
echo 'this is the text: <replaceme>' |
awk -v srch = "<replaceme>" -v repl = "${mytext//$'\n'/\\\\n}" '{gsub(srch,repl)} 1'
this is the text: hello\nhow are you
Замена BASH ${mytext//$'\n'/\\\\n}
заменит каждый экземпляр \n
на \\n
перед передачей этой строки в качестве аргумента awk
repl
.
Чистое решение awk (без bash):
echo 'this is the text: <replaceme>' |
awk -v srch = "<replaceme>" '
BEGIN {
repl = ARGV[1]
gsub(/\n/, "\\n", repl)
delete ARGV[1]
}
{
gsub(srch, repl)
} 1' "$mytext"
this is the text: hello\nhow are you
Вы специально ПРОСИТЕ awk преобразовать \n
в буквальную новую строку, используя -v
для установки переменных awk, поскольку интерпретация escape-последовательностей - это то, для чего предназначен -v
. Если это не то поведение, которое вам нужно, просто не делайте этого - вместо этого используйте ENVIRON[]
или ARGV[]
для заполнения переменных awk, чтобы переменная оболочки или содержимое строки передавались в awk как есть:
$ mytext=$'hello\nhow are you'
$ mytext2=${mytext//$'\n'/\\n}
$ echo 'this is the text: <replaceme>' |
old = "<replaceme>" mytext2 = "$mytext2" awk '
BEGIN { srch=ENVIRON["old"]; repl=ENVIRON["mytext2"] }
{ gsub(srch,repl,$0); print $0 }
'
this is the text: hello\nhow are you
$ mytext=$'hello\nhow are you'
$ mytext2=${mytext//$'\n'/\\n}
$ echo 'this is the text: <replaceme>' |
awk '
BEGIN { srch=ARGV[1]; repl=ARGV[2]; ARGV[1]=ARGV[2] = "" }
{ gsub(srch,repl,$0); print $0 }
' "<replaceme>" "$mytext2"
this is the text: hello\nhow are you
См. Как использовать переменные оболочки в скрипте awk? для получения дополнительной информации.
Обратите внимание: поскольку вы используете gsub()
для поиска и замены, вам все равно придется беспокоиться о метасимволах регулярного выражения, таких как .
или *
, в строке srch
и метасимволе обратной ссылки &
в строке repl
.
Если вы хотите выполнить буквальный поиск и замену строк, вам нужно либо избежать любых возможных метасимволов, например. (непроверено):
old = "<replaceme>" mytext2 = "$mytext2" awk '
BEGIN {
srch = ENVIRON["old"]
repl = ENVIRON["mytext2"]
gsub(/[^^\\]/, "[&]", srch)
gsub( /\/ , "&&", srch)
gsub( /\^/ , "\\&", srch)
gsub( /&/ , "\\&", repl)
}
{ gsub(srch,repl,$0); print $0 }
'
(см. Можно ли надежно экранировать метасимволы регулярных выражений с помощью sed для эквивалента sed и объяснения того, что делают эти gsub()
) или использовать строковые операторы (index()
и substr()
) вместо регулярного выражения+обратной ссылки (gsub()
).
Кстати, не очевидно, почему вы начинаете со строки hello\nhow are you
, содержащей два символа \n
, затем используете bash $'...'
, чтобы преобразовать ее в новую строку, затем используете ${mytext//$'\n'/\\n}
, чтобы преобразовать ее обратно в \n
, а затем вызываете awk с -v
для преобразуйте его обратно в новую строку, а затем спросите, как напечатать его как исходные два символа \n
. Вы делаете:
'hello\nhow are you'
-> \n
mytext=$'hello\nhow are you'
-> <newline>
mytext2=${mytext//$'\n'/\\n}
-> \n
awk -v repl = "$mytext2"
-> <newline>
awk '{... print ...}'
-> \n
(хочу)Похоже, вы совершаете слишком много конверсий! Вы могли бы избежать первых 2 или 3 конверсий в своем вопросе, просто начав с mytext2='hello\nhow are you'
или даже awk -v repl='hello\nhow are you'
.
Спасибо всем вам за ваши ответы! Оно работает.
Да, мой пример неочевиден, я хотел поделиться кратким примером, описывающим проблему. Я также не хотел копировать/вставлять код, связанный с компанией, в которой я работаю, поэтому я создал этот фиктивный пример. К сожалению, у меня нет никаких знаний о awk, я использовал -v, потому что нашел в Интернете пример использования переменной с -v.
Чтобы я мог решить свою проблему с помощью repl="${mytext//$'\n'/\\n}".
Да, я много конвертирую. Можем ли мы избежать этого и найти более приятное решение?
Фактически, мой реальный вариант использования:
Может ли awk принять содержимое файла в качестве аргумента?
Мое текущее решение, которое работает, но не элегантно Спасибо
сертификаты.json.tpl
{
"pkcs12": [
{
"name": "certificats_1-key",
"certificate-name": "certificats_1-cert",
"pkcs12": "<certificats_1>",
"password": "<password>"
},
{
"name": "certificats_2-key",
"certificate-name": "certificats_2-cert",
"pkcs12": "<certificats_2>",
"password": "<password>"
},
{
"name": "certificats_3-key",
"certificate-name": "certificats_3-cert",
"pkcs12": "<certificats_3>",
"password": "<password>"
}
],
"ca-certs": [
{
"name": "certificats_trusted",
"pem": "<certificats_trusted>"
}
]
}
password = "thisisasecret"
certificats_1=$(cat certificats_1.p12.base64)
certificats_2=$(cat certificats_2.p12.base64)
certificats_3=$(cat certificats_3.p12.base64)
certificats_trusted=$(cat certificats_trusted.pem)
cat certificats.json.tpl | \
awk -v srch = "<password>" -v repl = "$password" '{ gsub(srch,repl,$0); print $0 }' | \
awk -v srch = "<certificats_1>" -v repl = "$certificats_1" '{ gsub(srch,repl,$0); print $0 }' | \
awk -v srch = "<certificats_2>" -v repl = "$certificats_2" '{ gsub(srch,repl,$0); print $0 }' | \
awk -v srch = "<certificats_3>" -v repl = "$certificats_3" '{ gsub(srch,repl,$0); print $0 }' | \
awk -v srch = "<certificats_trusted>" -v repl = "${certificats_trusted//$'\n'/\\\\n}" '{ gsub(srch,repl,$0); print $0 }'
> certificats.json