Linux 如何在unix中搜索和替换特定列中的值

Linux 如何在unix中搜索和替换特定列中的值,linux,shell,perl,unix,aix,Linux,Shell,Perl,Unix,Aix,我正在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|a

我正在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

<>请参阅更多关于<代码> -v>代码>,以及为什么它比试图在脚本字符串中间插入变量更好。

<>在AWK中;
awk -v newval="$NEW_VAL_2" -v i="$i" '
  BEGIN{OFS="\t"}
  $1 == i { $2 = newval } 1' $FILE > newfile


<>请参阅更多关于<代码> -v>代码>,以及为什么它比试图在脚本字符串中间插入变量更好。

这里是Perl一个线性解决方案。在这里使用纯perl(带有模式匹配)比混合使用grep、awk和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

下面是一个perl单行程序解决方案。在这里使用纯perl(带有模式匹配)比混合使用grep、awk和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
作为第2和第3个字段的新值

下面是一个例子:

ITEM=instance102; NV2=100; NV3=80; sed -E -e "s/^${ITEM}(\\s+)(\\S+)(\\s+)(\\S+)(\\s*)\$/${ITEM}\\1${NV2}\\3${NV3}\\5/" $FILE

它还保留了原始的间距字符:可以是制表符、空格,也可以是制表符和空格的组合。即使不同的行使用不同的间距样式,它也会保持原始间距。

作为要修改的实例行。让
NV2
NV3
作为第2和第3个字段的新值

下面是一个例子:

ITEM=instance102; NV2=100; NV3=80; sed -E -e "s/^${ITEM}(\\s+)(\\S+)(\\s+)(\\S+)(\\s*)\$/${ITEM}\\1${NV2}\\3${NV3}\\5/" $FILE
它还保留了原始的间距字符:可以是制表符、空格,也可以是制表符和空格的组合。即使对不同的线使用不同的间距样式,它也会保持原始间距