我正在AIX中的Shell脚本上工作,该脚本具有一些代码来更新文本文件中的某些值。该文件的格式如下所示:
# cat $FILE
instance1 13 16
instance2 14 12
instance4 58 76
instance15 44 91
instance102 31 10
instance112 12 38
我正在尝试按实例名称搜索,并用新值替换第2列和第3列中的值我能够使用perl做到这一点,如下所示:
# for i in `cat $FILE|awk '{print $1}'`;do
# perl -pi -e "s/`grep -i $i $FILE|awk '{print $2}'`/$NEW_VAL_2/ if /$i/" $FILE
# perl -pi -e "s/`grep -i $i $FILE|awk '{print $3}'`/$NEW_VAL_3/ if /$i/" $FILE
# done
此方法有效,但后来我意识到它正在替换每次出现的值。例如,在最后一行中,它替换列2中的值,而且替换实例名称的后两个字符。
Example:
# i = instance112
# NEW_VAL_2 = 99
# perl -pi -e "s/`grep -i $i $FILE|awk '{print $2}'`/$NEW_VAL_2/ if /$i/" $FILE
Output:
instance199 99 38
如何通过实例名称搜索行并仅替换特定列中的值?
awk;
awk -v newval="$NEW_VAL_2" -v i="$i" '
BEGIN{OFS="\t"}
$1 == i { $2 = newval } 1' $FILE > newfile
有关How do I use shell variables in an awk script的更多信息,请参见-v
,为什么它比尝试在脚本字符串的中间插入变量更好。
这里是一个perl单线解决方案。与grep,awk和perl的混合使用相比,在这里使用纯perl(具有模式匹配)更加容易和快捷。
$ export FILE=foo
$ cat $FILE
instance1 13 16
instance2 14 12
instance4 58 76
instance15 44 91
instance102 31 10
instance112 12 38
$ export i=instance112
$ export NEW_VAL_2=99
$ export NEW_VAL_3=11
$ perl -lne 'if ( m{ \A $ENV{i} \t }xms ) { $_ = join "\t", @ENV{ qw( i NEW_VAL_2 NEW_VAL_3 ) }; } print; ' foo
instance1 13 16
instance2 14 12
instance4 58 76
instance15 44 91
instance102 31 10
instance112 99 11
让ITEM
为要修改的实例行。令NV2
和NV3
为第二和第三字段的新值。
这里是一个例子:
ITEM=instance102; NV2=100; NV3=80; sed -E -e "s/^${ITEM}(\\s+)(\\S+)(\\s+)(\\S+)(\\s*)\$/${ITEM}\\1${NV2}\\3${NV3}\\5/" $FILE
它还保留了原始的空格字符:制表符,空格或制表符和空格的组合。即使对于不同的线条使用不同的间距样式,它也可以保持原始间距。