比较两行并打印两个文件中不匹配的单词

比较两行并打印两个文件中不匹配的单词

我有两个文件,假设为 file1 和 file2

文件1有 ”eipassoc-03cd9117d7188d2 eipasoc-47367a3f eipasoc-bbbddc3 eipassoc-10bbfb6“每个都是空格分隔的
文件2有 ”eipasoc-47367a3f eipassoc-10bbfb6“每个都是空格分隔的

我想打印“eipassoc-03cd9117d7188d2 eipasoc-bbbddc3“ 在文件3.因为我试图做的只是从 file1 中找出不匹配的单词。

我一直在尝试使用“awk”、“for 循环”、“while 循环”,但无法找到解决方案。有任何知道如何减去并只得到不匹配的吗?

谢谢你们。

答案1

我使用了组合来让它做你想做的事情:

使用以下命令生成数组:

l1=$(cut -d" " -f 1- src1.txt)
l2=$(cut -d" " -f 1- src2.txt)

使用如下命令来比较两个数组:

l1=$(cut -d" " -f 1- src1.txt) && l2=$(cut -d" " -f 1- src2.txt) && echo "${l1[@]}" "${l2[@]}" | tr ' ' '\n' | sort | uniq -u | xargs -L 2 > result.txt

结果:

a c

信息:

  • echo "${l1[@]}" "${l2[@]}" | tr ' ' '\n':翻译 echo 命令的输出,并将每个空格替换为换行符

  • | sort | uniq -u:对输出进行排序并找出唯一值

  • | xargs -L 2 > result.txt:将最后一条命令的结果传递到结果文件中

  • l1=$(cut -d" " -f 1- src1.txt)l2=$(cut -d" " -f 1- src2.txt):生成数组

样品测试:

george@george-Inspiron-5570:/tmp$ echo "eipassoc-03cd9117d7188d2 eipasoc-47367a3f eipasoc-bbbddc3 eipassoc-10bbfb6" > f1.txt
george@george-Inspiron-5570:/tmp$ echo "eipasoc-47367a3f eipassoc-10bbfb6" > f2.txt
george@george-Inspiron-5570:/tmp$ l1=$(cut -d" " -f 1- f1.txt) && l2=$(cut -d" " -f 1- f2.txt) && echo "${l1[@]}" "${l2[@]}" | tr ' ' '\n' | sort | uniq -u | xargs -L 2 > result.txt
george@george-Inspiron-5570:/tmp$ cat result.txt 
eipasoc-bbbddc3 eipassoc-03cd9117d7188d2
george@george-Inspiron-5570:/tmp$ 

答案2

首先记住,给定任意两个列表,我们可以计算 3 种类型的差异:

  1. 列表 1 中存在但不在列表 2 中的元素
  2. 列表 2 中存在但不在列表 1 中的元素
  3. 存在于一个列表中但不存在于两个列表中的元素(对称差异)

逐行比较列表(文件)的标准 Unix 工具是comm。它通常输出 3 列 - 来自man comm

   With  no  options,  produce  three-column  output.  Column one contains
   lines unique to FILE1, column two contains lines unique to  FILE2,  and
   column three contains lines common to both files.

对应于第三种差分的第一、第二和补集。它还要求其输入是经过排序的。

$ comm <(tr ' ' '\n' < file1 | sort) <(tr ' ' '\n' < file2 | sort)
a
                b
c
                d

(这里有一个空的中间列,因为对于您的示例输入,没有第二种类型的差异)。

假设您想要的是第一类差异(列表 1 中存在但不在列表 2 中的元素),我们可以告诉comm它抑制其他列,然后将结果粘贴回以空格分隔的列表中:

$ comm -23 <(tr ' ' '\n' < file1 | sort) <(tr ' ' '\n' < file2 | sort) | paste -sd ' '
a c

如果你不喜欢这种方法,那么 perl 有一个列表::比较您可以使用的模块:

$ cat file1 file2 | perl -MList::Compare -alne '
    push @{ $a[$.] }, @F 
    }{ 
    $lc = List::Compare->new($a[1], $a[2]); 
    print join " ", $lc->get_Lonly()
  '
  a c

其他语言(python、ruby 等)可能具有同等的功能。

答案3

看起来您有两个文件,每个文件都有很长的一行,其中包含(空格)分隔的标记。 diff 工具非常适合行匹配。对于行内的项目,您必须更具创造力。

例如

:~$ cat file1
a b c d

:~$ cat file2
b d

:~$ cat file1 | sed 's/ /\n/g' |grep -vf <(cat file2|sed 's/ /\n/g') | tr '\n' ' '; echo

a c 

我们可以使用另一个面向行的工具,通过使用作为临时文件提供的行列表来从输入流中排除行。

 sed 's/ /\n/g' 

将空格转换为新行

 grep -v 
  • 从输入流中排除过滤条件

    grep -f

  • 使用所提供文件中的条件/行列表

    <(...)

从子进程输出创建文件句柄

 tr '\n' ' '

将新行转换回空格。但是,末尾没有行,因此我们添加了尾随回显。

使用 [g]AWK 可以实现相同的效果,因为它具有内置映射。您必须将记录分隔符设置为空格。

如果使用更新后的示例,我们得到:

>cat file1
eipassoc-03cd9117d7188d2 eipasoc-47367a3f eipasoc-bbbddc3 eipassoc-10bbfb6
>cat file2
eipasoc-47367a3f eipassoc-10bbfb6
>cat file1 | sed 's/ /\n/g' |grep -vf <(cat file2|sed 's/ /\n/g') | tr '\n' ' '; echo
eipassoc-03cd9117d7188d2 eipasoc-bbbddc3 
>
>

如果您倾向于使用 AWK,这里有一个示例:

>cat file1
eipassoc-03cd9117d7188d2 eipasoc-47367a3f eipasoc-bbbddc3 eipassoc-10bbfb6
>cat file2
eipasoc-47367a3f eipassoc-10bbfb6
>cat file1 | sed 's/ /\n/g' |grep -vf <(cat file2|sed 's/ /\n/g') | tr '\n' ' '; echo
eipassoc-03cd9117d7188d2 eipasoc-bbbddc3 
>
>

在这里我使用了一个 hack 将第一个文件视为查找(NR==FNR)并将读取的行存储在映射中,然后根据查找检查非第一个文件。您可以免费获得记录分离,但代码变得晦涩难懂,因为它依赖于副作用

答案4

ID=$(aws ec2 describe-addresses --region us-west-2 --query '地址[].AssociationId[]' --输出文本 >> AId.txt)
IP=$(aws ec2 describe-addresses --region us-west-2 --query '地址[].PublicIp[]' --输出文本 >> OIP.txt)

读取 -a 数组 <<< $(cat AId.txt)
touch NR.txt
for i in ${array[@]};
do
echo $(aws ec2 describe-addresses --region us-west-2 --filters "Name=association-id,Values=$i" --query 'Addresses[].PublicIp[]' --output text) >> NR.txt
完成

读取 -a array1 <<< $(cat OIP.txt)
touch RIps.txt
for i in ${array1[@]};
do
echo $i >> RIps.txt
done

l1=$(cut -d" " -f 1- RIps.txt)
l2=$(cut -d" " -f 1- NR.txt)
echo "${l1[@]}" "${l2[@]}" | tr ' ' '\n' | sort | uniq -u | xargs -L 2 > result.txt

前一个给出的所有答案都是正确的,除了我正在加载的文件有一个未知字符,这就是为什么我尝试将它们逐行存储在文件中而不是将所有内容都存储在一行中。然后代码就起作用了。谢谢大家。

相关内容