覆盖文件内容

覆盖文件内容

我有两个文件,file1.txtfile2.txtfile1.txt是:

perimeter a=10
perimeter b=15
perimeter c=20

file2.txt是:

perimeter a=12
perimeter b=14

让我知道sed或 Perl 覆盖的值file1.txt

输出file1.txt应该是这样的:

perimeter a=12
perimeter b=14
perimeter c=20

我使用了一系列命令,例如

sed -i -e '/parameter//d r file1.txt' file2.txt
awk -F, 'NR==FNR{a[$1]=$0;next;}a[$1]{$0=a[$1]}1' file1.txt file2.txt
awk -F, 'NR==FNR{a[$1]=$0;next;}a[$1]{$0=a[$1]}1' file2.txt file1.txt

这些都无济于事。

答案1

也许像这样?将其保存为 egscript.pl并运行 via perl script.pl file1.txt file2.txt,它会产生您想要的输出。我对文件格式做了一些假设,例如没有需要保留的空行或注释。

#!/usr/bin/env perl
use warnings;
use strict;
use Tie::IxHash;

tie my %hash, 'Tie::IxHash';
while (<>) {
    chomp;
    my ($k,$v) = split /=/, $_, 2;
    $hash{$k} = $v;
}
for my $k (keys %hash) {
    print "$k=$hash{$k}\n";
}

更新:不依赖以下版本的Tie::IxHash

use warnings;
use strict;

my (%hash, @keys);
while (<>) {
    chomp;
    my ($key,$value) = split /=/, $_, 2;
    push @keys, $key unless exists $hash{$key};
    $hash{$key} = $value;
}
for my $key (@keys) {
    print "$key=$hash{$key}\n";
}

这也可以浓缩成一句话:

perl -F= -anle 'exists$h{$F[0]}||push@k,$F[0];$h{$F[0]}=$F[1];END{print"$_=$h{$_}"for@k}' file1.txt file2.txt

然而请注意,与脚本不同,如果有多行包含 ,此单行代码将无法正常工作=

答案2

您必须对如何实际重写文件保持谨慎。不要这样做:

some_program < file1 > file1

因为 shell 负责处理重定向启动该程序时,>重定向将截短文件程序就有机会读取它。

以下是一些替代方案:

  1. 明确写入临时文件,然后覆盖原始文件

    tmpfile=$(mktemp)
    some_program < file1 > "$tmpfile" && mv "$tmpfile" file1
    

    使用&&,所以你只mv 如果程序成功退出。

  2. 使用sponge命令moreutils包裹

    some_program < file1 | sponge file1
    
  3. 如果您使用 GNU awk,您可以使用扩展-i inplace,但您需要稍微调整一下程序:

    gawk -i inplace -F= '
        NR == FNR {a[$1] = $0; print; next} 
        $1 in a {$0 = a[$1]} 
        1
    ' file{2,1}.txt
    

选项 2 和 3 也使用临时文件,但会为您处理细节。

相关内容