目前,我正在使用 AWK 查找并替换字符串前三次出现的部分内容。该字符串的格式如下,文件中有许多这样的字符串:
func(tempID="39849235",count='12');
使用此链接,我找到了一种使用 AWK 查找和替换字符串前三个实例的方法。我将其更改为我需要它执行的操作,我的脚本片段如下:
id=12349876
awk 'BEGIN {matches=0}
matches < 3 && /.*tempID.*/ { sub(/tempID="[0-9]+"/,"tempID='"$id"'"); matches++ }
{ print $0 }' filName.py >filName.py.changed
上述代码的目的是匹配任何包含 tempID 的行,并将分配给 tempID 的数字替换为变量中保存的值$id
。查找和替换工作正常,但我似乎遇到的一个问题是,无论我如何构造它,输出都会打印不带引号的 $id。我尝试过转义引号并添加单个勾号,但无论如何,该行都会更改为:
func(tempID=39849235,count='12');
我尝试删除替换部分周围的双引号并将其构造为tempID="$id"
,但不幸的是,这只是用字符串替换了 ID 号$id
。
请告诉我是否有办法找到并替换 tempID 值并用引号括起来。我没有被 AWK 所困扰,所以使用任何其他实用程序(例如 sed)的任何其他方法也可以正常工作。
答案1
在您的命令中,有引号被 shell 解释并删除,有引号被 解释并删除awk
,那么您需要保留引号。您应该对它们进行转义:
id=12349876
awk 'BEGIN {matches=0}
matches < 3 && /.*tempID.*/ { sub(/tempID="[0-9]+"/,"tempID=\"'"$id"'\""); matches++ }
{ print $0 }' filName.py >filName.py.changed # ^^ here ^^
解释。你的原始命令如下
awk 'BEGIN {matches=0} matches < 3 && /.*tempID.*/ { sub(/tempID="[0-9]+"/,"tempID='"$id"'"); matches++ } { print $0 }'
# ^ these quotes are seen by the shell and don't get to awk ^^ ^^ ^
# these quotes get to awk and serve their purpose there ^ ^ ^ ^
# this variable is expanded by the shell and gets to awk as its value ^^^
这是改进后的命令:
awk 'BEGIN {matches=0} matches < 3 && /.*tempID.*/ { sub(/tempID="[0-9]+"/,"tempID=\"'"$id"'\""); matches++ } { print $0 }'
# ^ these quotes are seen by the shell and don't get to awk ^^ ^^ ^
# these quotes get to awk and serve their purpose there ^ ^ ^ ^
# these quotes will appear in the output thanks to being escaped ^ ^
# this variable is expanded by the shell and gets to awk as its value ^^^
为了减少引用狂潮,您可以使用-v
选项将变量传递给awk
。然后,您无需在序列中间关闭并重新打开单引号,只需让 shell 扩展$id
。相反,未引用的(如awk
所见)id
会自行扩展awk
。我们需要添加的双引号应该像以前一样进行转义:
id=12349876
awk -v id="$id" 'BEGIN {matches=0}
matches < 3 && /.*tempID.*/ { sub(/tempID="[0-9]+"/,"tempID=\""id"\""); matches++ }
{ print $0 }' filName.py >filName.py.changed
答案2
为了实现您想要做的事情,您需要:
对于双引号:
"
AWK:在其他双引号内转义双引号。
$1 $2
=>foobar
$1" __"$2"__"
=>foo __bar__
$1" \""$2"\""
=>foo "bar"
对于单引号:
Shell:退出你的整个 awk 脚本,使用其中
'…'
的另一组。 =>'…'
'escaped 'unescaped' escaped'
'$LINUX '$OSTYPE' $CPUTYPE'
$LINUX linux-gnu $CPUTYPE
Shell:Escape
'
您想要按字面意思打印。
'apostrophe that'\''s literal'
=>apostrophe that's literal
例如
echo foo bar | awk '{print "\""$1"\" '\''"$2"'\''"}'
"foo" 'bar'