Linux 如何在考虑其他文件的情况下显示文件的内容?

Linux 如何在考虑其他文件的情况下显示文件的内容?,linux,bash,shell,sed,awk,Linux,Bash,Shell,Sed,Awk,我有一个包含以下内容的文件1 {"name":"clio5", "value":"13"} {"name":"citroen_c4", "value":"23"} {"name":"citroen_c3", "value":"12"} {"name":"golf4", "value":"16"} {"name":"golf3", "value":"8"} {"name":"clio5", "value":"14"} {"name":"citroen_c4", "value":"25"} {"n

我有一个包含以下内容的文件1

{"name":"clio5", "value":"13"}
{"name":"citroen_c4", "value":"23"}
{"name":"citroen_c3", "value":"12"}
{"name":"golf4", "value":"16"}
{"name":"golf3", "value":"8"}
{"name":"clio5", "value":"14"}
{"name":"citroen_c4", "value":"25"}
{"name":"golf4", "value":"18"}
我有一个包含以下内容的文件2

{"name":"clio5", "value":"13"}
{"name":"citroen_c4", "value":"23"}
{"name":"citroen_c3", "value":"12"}
{"name":"golf4", "value":"16"}
{"name":"golf3", "value":"8"}
{"name":"clio5", "value":"14"}
{"name":"citroen_c4", "value":"25"}
{"name":"golf4", "value":"18"}
我想执行一个shell命令来显示file1和file2的内容。如果文件1和文件2中都存在名称,那么我只想显示文件2的相关行

因此,输出应如下所示:

$command taking account file1 file2
{"name":"clio5", "value":"14"}
{"name":"citroen_c4", "value":"25"}
{"name":"citroen_c3", "value":"12"}
{"name":"golf4", "value":"18"}
{"name":"golf3", "value":"8"}
该命令不应编辑文件1或文件2

编辑

文件1和文件2的内容格式完全相同:

{"name":"any", "value":"xx"}
命令应该尽可能简单


该命令可能包含grep、sed、awk,输入看起来像JSON。使用适当的工具,Perl库:

#!/usr/bin/perl
use warnings;
use strict;

use JSON qw(from_json to_json);

my %hash;

for my $file (qw/file1 file2/) {
    open my $FH, '<', $file or die $!;
    while (<$FH>) {
        my $j = from_json($_);
        $hash{$j->{name}} = $j->{value} // $j->{new_value};
    }
}

while (my ($name, $value) = each %hash) {
    print to_json({name => $name, value => $value}), "\n";
}
正如JSON所说,它相当于您的预期输出,因此如果您总是使用适当的库,您将不会注意到差异。如果没有,您必须进一步调整代码

或者,如果您确实想使用sed:

sed 's%\({"name":"[^"]*", \)"new_value":\("[^"]*"\)}%s/\1"value.*/\1"value":\2}/%' file2 \
    | sed -f- file1
第一个sed调用将file2转换为一个sed脚本,该脚本将替换file1中的旧值。

一种方法是使用join将名称字段上的两个文件连接起来,然后使用awk更改值。如下所示:

$ join -t, -a1 <(sort file1) <(sort file2) | awk -F, -vOFS=, '{if($3){$2=$3;NF-=1}}1' | sed 's/new_value/value/g'
{"name":"citroen_c3", "value":"12"}
{"name":"citroen_c4", "value":"25"}
{"name":"clio5", "value":"14"}
{"name":"golf3", "value":"8"}
{"name":"golf4", "value":"18"}
while IFS= read -r line
do
    if [[ $line =~ name\":\"([^\"]*)\" ]]
    then
        name=${BASH_REMATCH[1]}
        newVal=$(grep "\"name\":\"$name\"" file2 | sed 's/^.*"\([^"]\+\)"}$/\1/g')
        if [[ -z $newVal ]]
        then
            echo "$line"
        else
            echo "{\"name\":\"$name\", \"value\":\"$newVal\"}"
        fi
    fi
done < file1
输出:

{"name":"clio5", "value":"14"}
{"name":"citroen_c4", "value":"25"}
{"name":"citroen_c3", "value":"12"}
{"name":"golf4", "value":"18"}
{"name":"golf3", "value":"8"}

对我的解决方案进行了简单的更改,它似乎起到了作用:

输出的顺序重要吗?否则,您可以使用排序:

更改是添加-key=1。这意味着它将在第一列上排序,直到每行的第一个空格-当另一个排序发现两个相等时,s使它不在行的其余部分使用排序。文件的顺序决定了匹配时将使用的文件行

这将输出按字母顺序排序的结果。看起来输入已经是了,在这种情况下,我相信它应该和你描述的完全一样。否则,它将更改要排序的行的顺序。不确定这是否是个问题?

以下是awk的一种方法:

测试:
格式化很容易修复,只需用自定义格式替换为_json即可。更严重的问题可能是它不能维持秩序。。。但是OP没有说明他想要什么。让我们等一下。我想要一些简单的东西。我更新了我的问题以解释更多内容。@MOHAMED:我添加了一个简单的sed解决方案。sed命令返回错误:sed:无法打开“-”:没有这样的文件或directory@MOHAMED:然后将第一个sed命令的输出重定向到带有>temp_file的temp文件,然后在第二个sed中使用-f temp_file。我想要一些简单的东西。我更新了我的问题来解释更多。我的linuxif行中没有join。如果存在,可能应该解释得更清楚一点,不是存在相同的行,而是存在一个同名的行:@SvendHansen是的,没错。如果输出的顺序不重要,我想我的解决方案现在可能会起作用:干净简单的解决方案+1.
awk -F"[:,]" '
NR==FNR { name[$2]=$0;next }
($2 in name) { delete name[$2]; print $0 }
END { for (left in name) print name[left] }' file1 file2
$ head file*
==> file1 <==
{"name":"clio5", "value":"13"}
{"name":"citroen_c4", "value":"23"}
{"name":"citroen_c3", "value":"12"}
{"name":"golf4", "value":"16"}
{"name":"golf3", "value":"8"}

==> file2 <==
{"name":"clio5", "value":"14"}
{"name":"citroen_c4", "value":"25"}
{"name":"golf4", "value":"18"}

$ awk -F"[:,]" '
NR==FNR { name[$2]=$0;next }
($2 in name) { delete name[$2]; print $0 }
END { for (left in name) print name[left] }' file1 file2
{"name":"clio5", "value":"14"}
{"name":"citroen_c4", "value":"25"}
{"name":"golf4", "value":"18"}
{"name":"golf3", "value":"8"}
{"name":"citroen_c3", "value":"12"}