用另一个文件中指定的值替换字段

Posted

技术标签:

【中文标题】用另一个文件中指定的值替换字段【英文标题】:Replace a field with values specified in another file 【发布时间】:2012-09-06 04:25:15 【问题描述】:

我有一个文件,其中包含单词之间的映射。我必须引用该文件并将这些单词替换为某些文件中的映射单词。例如,下面的文件具有映射的单词表,如

1.12.2.4               1
1.12.2.7               12
1.12.2.2               5
1.12.2.4               4
1.12.2.6               67
1.12.2.12              5

我会有很多文件包含这些关键词 (1.12.2.*)。我想搜索这些关键词并将这些词替换为从此文件中获取的相应映射。如何在 shell 中执行此操作。假设一个文件包含以下几行说

The Id of the customer is 1.12.2.12. He is from Grg. 
The Name of the machine is ASB
The id is 1.12.2.4. He is from Psg.

执行脚本后,数字“1.12.2.12”和“1.12.2.4”应替换为5和4(参考主文件)。谁能帮帮我?

【问题讨论】:

【参考方案1】:

您可以让sed 为您编写一个sed 脚本:

映射:

cat << EOF > mappings
1.12.2.4               1
1.12.2.7               12
1.12.2.2               5
1.12.2.4               4
1.12.2.6               67
1.12.2.12              5
EOF

输入文件:

cat << EOF > infile
The Id of the customer is 1.12.2.12. He is from Grg. 
The Name of the machine is ASB
The id is 1.12.2.4. He is from Psg.
EOF

根据映射生成脚本(GNU sed):

sed -r -e 's:([^ ]*) +(.*):s/\\b\1\\b/\2/g:' mappings

输出:

s/\b1.12.2.4\b/1/g
s/\b1.12.2.7\b/12/g
s/\b1.12.2.2\b/5/g
s/\b1.12.2.4\b/4/g
s/\b1.12.2.6\b/67/g
s/\b1.12.2.12\b/5/g

与另一个 sed (GNU sed) 一起评估:

sed -r -e 's:([^ ]*) +(.*):s/\\b\1\\b/\2/g:' mappings | sed -f - infile

输出:

The Id of the customer is 5. He is from Grg. 
The Name of the machine is ASB
The id is 1. He is from Psg.

请注意,映射被视为正则表达式,例如点 (.) 可以表示任何字符,并且可能需要在映射文件中或在生成 sed 脚本时进行转义。

【讨论】:

这不起作用..我在执行时遇到这个错误.. sed: -e expression #1, char 26: invalid reference \2 on `s' command's RHS 忘记了我将sed 别名为sed -r。我已将-r 添加到相关表达式中。 我仍然得到错误.. sed: file - line 1: unknown command: `.' !!我猜有些东西是错的.. @user1667630:您使用的是什么版本的 sed?我刚刚用 FreeBSD sed 对此进行了测试,如果您将 -f - 替换为 -f /dev/stdin,它就可以工作。在别处提到,匹配key的词边界是个好主意,所以我添加了它,但是现在生成的表达式不起作用。如果可以的话,我认为您应该尝试使用 GNU sed,通常称为 gsed,它为您提供了更多选择。 在最坏的情况下,将生成的脚本保存到临时文件,运行sed -f /tmp/temporary.sed,然后删除临时文件。【参考方案2】:

一种使用GNU awk的方式:

awk 'FNR==NR  array[$1]=$2; next   for (i in array) gsub(i, array[i]) 1' master.txt file.txt

结果:

The Id of the customer is 5. He is from Grg.
The Name of the machine is ASB
The id is 4. He is from Psg.

将输出保存到文件:

awk 'FNR==NR  array[$1]=$2; next   for (i in array) gsub(i, array[i]) 1' master.txt file.txt > name_of_your_output_file.txt

说明:

FNR==NR  ...    # FNR is the current record number, NR is the record number
                  # so FNR==NR simply means: "while we process the first file listed
                  # in this case it's "master.txt"
array[$1]=$2      # add column 1 to an array with a value of column 2
next              # go onto the next record

                 # this could be written as: FNR!=NR
                  # so this means "while we process the second file listed..."
for (i in array)  # means "for every element/key in the array..."
gsub(i, array[i]) # perform a global substitution on each line replacing the key
                  # with it's value if found
1                # this is shorthand for 'print'

添加单词边界使匹配更加严格:

awk 'FNR==NR  array[$1]=$2; next   for (i in array) gsub("\\<"i"\\>", array[i]) 1' master.txt file.txt

【讨论】:

显然,如果master.txt 中的键太相似,这将中断 嗨.. 我希望将这些值写入文件中。我怎样才能做到这一点?我是shell脚本的新手。对不起:(..提前谢谢.. 实际上,即使部分行匹配,gsub 也会替换。就像假设映射文件包含像 10.1.1.12 1 这样的条目,而我需要更改的文件有两个条目。 10.1.1.12 和 10.1.1.1234 那么这将替换两条线..如何摆脱它? @steve:我错过了第一块中的next,所以请忽略我之前的评论。 @user1667630:要匹配整个单词,您可以在匹配时添加单词边界,例如:gsub("\\&lt;" i "\\&gt;", array[i]);并且只让第一个匹配生效可能是一个想法:`if( gsub("\\", array[i]) ) break; @Thor:感谢您的出色建议。我不知道这种语法:-)【参考方案3】:

由于您没有提供任何示例,我想这就是您想要的:

输入文件

> cat temp
1.12.2.4  1
1.12.2.7  12
1.12.2.2  5
1.12.2.4  4
1.12.2.6  67
1.12.2.12  5

要替换的文件

> cat temp2
The Id of the customer is 1.12.2.12. He is from Grg. 
The Name of the machine is ASB
The id is 1.12.2.4. He is from Psg.

输出

> temp.pl
The Id of the customer is 5. He is from Grg. 
The Name of the machine is ASB
The id is 4. He is from Psg

>

下面是 perl 脚本。

#!/usr/bin/perl

use strict;
use warnings;

my %hsh=();

open (MYFILE, 'temp');
open (MYFILE2, 'temp2');

while (<MYFILE>) 
my@arr = split/\s+/;
$hsh$arr[0] = $arr[1];

my $flag;
while(<MYFILE2>)

$flag=0;
my $line=$_;
foreach my $key (keys %hsh)

   if($line=~/$key/)
   
    $flag=1; 
    $line=~s/$key/$hsh$key/g;
    print $line;
   

  if($flag!=1)
  
  print $line;
  $flag=0;
  

close(MYFILE);
close(MYFILE2);

【讨论】:

以上是关于用另一个文件中指定的值替换字段的主要内容,如果未能解决你的问题,请参考以下文章

用另一个文件中的值替换一个文件不能正常工作

如何让红移为复制命令中指定的字段添加当前时间

c语言:如何将字符串中指定的字符替换为另一个指定字符

php 通过 strtr 方法来替换文本中指定的内容

将列表中的值更改为字典中指定的值?

linux下如何将第一行中指定的字符全部替换掉