我想创建一个包含动态凭据的配置文件模板。副本应保留结构,但值替换为空字符串(即 "(。我为此目的使用awk
。
awk -v dq=""" '{ if($NF ~ /^[&|*|n]/ || $1 == $NF) print $0; else {$NF=""; print $0 dq dq;} }' .config.yaml >> .config_temp.yaml
问题出在 else 语句中。当我设置$NF=""
前导空白不再打印时。如果我没有将最后一个字段设置为空字符串,我就不会观察到这种行为,但显然不会收到预期的输出(见下文(。
如何在保留前导空格的同时将最后一个字段设置为空字符串?
我不想手动添加许多空格,因为意图各不相同。
config.yaml(Input(
DEVELOPMENT: &development
<<: *common
check_access_token: False
database:
mongodb:
database: test
hostname: localhost
port: 27017
username: ""
password: ""
collection:
col_1: test_1
col_2: test_2
col_3: test_3
col_4: test_4
conf_temp.yaml(实际输出(
DEVELOPMENT: &development
<<: *common
check_access_token: ""
database:
mongodb:
database: ""
hostname: ""
port: ""
username: ""
password: ""
collection:
property: ""
ctrl_voc: ""
form: ""
user: ""
预期产出
DEVELOPMENT: &development
<<: *common
check_access_token: ""
database:
mongodb:
database: ""
hostname: ""
port: ""
username: ""
password: ""
collection:
property: ""
ctrl_voc: ""
form: ""
user: ""
编辑(在Sundeep的重播之后(
谢谢你的回答。它几乎按照我的预期工作。但是,我收到的输出与您不同。如果我打电话
awk -F'[ ]' -v dq=""" 'NF>1 && $NF !~ /^[*&]|:$/{$NF = dq dq} 1' .conf.yaml
我收到以下输出:
DEVELOPMENT: &development
<<: *common
check_access_token: ""
"" <--
"" <--
database: ""
hostname: ""
port: ""
username: ""
password: ""
"" <--
property: ""
ctrl_voc: ""
form: ""
user: ""
缩进符合预期,但上层的键被引号取代(请参阅箭头(。
如果我将您的第二个建议与sed
一起使用,我会收到相同的输出.
请参阅 awk 的默认字段分隔符,以了解当FS
具有默认值或设置为单个空格字符时会发生什么情况。
您可以通过使用其他方式来传达单个空格来避免它,例如[ ]
$ awk -F'[ ]' -v dq=""" 'NF>1 && $NF !~ /^[*&]|:$/{$NF = dq dq} 1' ip.txt
DEVELOPMENT: &development
<<: *common
check_access_token: ""
database:
mongodb:
database: ""
hostname: ""
port: ""
username: ""
password: ""
collection:
col_1: ""
col_2: ""
col_3: ""
col_4: ""
NF>1
避免更改空行$NF !~ /^[*&]|:$/
检查最后一个字段是否以*
或&
开头,或者是否以:
结尾- 如果同时满足上述两个条件,请将"最后一个字段"设置为"
""
1
是打印$0
内容的惯用方法
对于给定的示例,您还可以使用:
sed '/:$/! s/ [^*&][^ ]*$/ ""/' ip.txt
问题:如何在不更改原始字段分隔符的情况下更新字段。
根据 awk POSIX 标准,当您使用$i = expr
更新字段时,它会导致重新计算 $0 的值,字段由OFS
的值分隔。
对于任何不是 ere的字段分隔符,解决方案很简单。更改字段n
按如下方式完成:
awk 'BEGIN{FS=OFS="string"}
{$n="new_value"}
{ ... }' file
对于其他字段分隔符,这有点问题:
- 如果
FS=" "
(默认值(,则忽略记录前后的任何间距,使用制表符和字段的任意组合 - 如果
FS="ere"
扩展正则表达式,您并不真正知道字段分隔符是什么。如果FS="fo*
,它可以是从f
到fooooooo
的任何内容。
在POSIX awk中,你需要做一些讨厌的操作:
awk 'BEGIN{FS="ere"}
# split original record
{ split($0,a,FS) }
# update field value
{ a[n]="new_value" }
# rebuild record
{
match($0,$1); rec=substr($0,1,RSTART-1); t=substr($0,RSTART+RLENGTH)
for(i=1;i<NF;i++) {
match(t,$(i+1)); rec = rec a[i] substr(t,1,RSTART-1)
t=substr(t,RSTART+RLENGTH)
}
$0 = rec a[NF] t
}
{ ... }' file
在 GNU awk 中,你可以以更通用的方式使用split
,因为它有一个扩展来保存原始分隔符:
awk 'BEGIN{FS="ere"}
# split original record
{ split($0,a,FS,f) }
# update field value
{ a[n]="new_value" }
# rebuild record
{ rec=f[0]; for(i=1;i<=NF;i++) rec=rec a[i] f[i]; $0 = rec }
{ ... }' file
一般评论:GNU awk 确实可以从反转split
命令并执行combine
的例程中受益