用另一个文件中指定的值替换字段
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("\\<" i "\\>", 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);
【讨论】:
以上是关于用另一个文件中指定的值替换字段的主要内容,如果未能解决你的问题,请参考以下文章