【问题标题】:How can i display the first five lines that differ between 2 files, in a shell script?如何在 shell 脚本中显示两个文件之间不同的前五行?
【发布时间】:2020-03-16 10:39:00
【问题描述】:

我尝试过使用 2 个数组来比较这 2 个文件,但我是菜鸟,我不知道该怎么做:

vec_fis_1=`cat fisier.txt`
vec_fis_2=`cat fisier1.txt`
echo $vec_fis_2
echo $vec_fis_1
for i in ${vec_fis_1[@]}
do
        for j in ${vec_fis_2[@]}
        do
                if ( "$i" == "$j" )
                then
                        echo $i
                        echo $j
                fi
        done
done

【问题讨论】:

  • shellcheck.net 检查您的脚本。将diffhead -n5 一起使用。
  • 此命令显示两个文件的前 5 行,但我只需要文件之间不同的前 5 行。
  • 文件排序了吗?
  • 不,他们不是。
  • 因此,最简单的方法可能是首先将 sort 两个文件放入临时文件,然后 diff 它们,正如@KamilCuk 所暗示的那样。您需要将参数更改为 diff 或运行 diff 到 grepawk 的输出,以允许 diff 命令生成的各种信息行。

标签: arrays linux shell file ubuntu


【解决方案1】:

不要使用反引号`。请改用$(..)

所以,不要使用if ( "$i" == "$j" ),而是使用if [ "$i" != "$j" ]

vec_fis_1vec_fis_2 不是数组 - ${vec_fis_1[@]}$vec_fis_1 相同。

要将文件读入数组,请使用readarray

要遍历文件中的行,请使用while read loop,请参阅bashfaq how to read a file line by line

while IFS= read -r l1; do
     while IFS= read -r l2; do
         if [ "$l1" != "$l2" ]; then
            printf "%s\n" "$l1"
            printf "%s\n" "$l2"
         fi
     done < fisier1.txt
done < fisier.txt

我只需要具有相同“行索引”的行之间的差异

所以同时读取两个文件。

while IFS= read -r -u3 l1 && 
         IFS= read -r -u4 l2; do
    if [ "$l1" != "$l2" ]; then
        printf "%s\n" "$l1"
        printf "%s\n" "$l2"
     fi
done 3< fisier.txt 4< fisier1.txt

您也可以处理不同的行数。我有这个(相当冗长)的想法:

while true; do

    IFS= read -r -u3 l1
    l1valid=$?
    IFS= read -r -u4 l2
    l2valid=$?
    if ((l1valid != 0 || l2valid != 0)); then
        if ((l1valid != 0 && l2valid == 0)); then
           echo "file1 is longer then file2"
        elif ((l1valid == 0 && l2valid != 0)); then
           echo "file1 is shorter then file2"
        fi # l1valid != 0 && l2valid != 0 - all fine
        break;
    fi

    if [ "$l1" != "$l2" ]; then
        printf "%s\n" "$l1"
        printf "%s\n" "$l2"
     fi

done 3< fisier.txt 4< fisier1.txt

或喜欢:

while
    IFS= read -r -u3 l1
    l1valid=$?
    IFS= read -r -u4 l2
    l2valid=$?
    if ((l1valid != 0 && l2valid == 0)); then
       echo "file1 is longer then file2"
    elif ((l1valid == 0 && l2valid != 0)); then
       echo "file1 is shorter then file2"
    fi
    (( l1valid == 0 && l2valid == 0 ))
do
    if [ "$l1" != "$l2" ]; then
        printf "%s\n" "$l1"
        printf "%s\n" "$l2"
     fi
done 3< fisier.txt 4< fisier1.txt

请注意,bash 循环非常慢,使用 awk 会快很多:

awk -vother="fisier1.txt" '{ t=$0; getline < (other); if (t != $0) print $0 RS t }' fisier.txt

【讨论】:

  • 但是我该怎么做,而不是第二个,只是有一个 if 从第二个文件中读取该行,因为我不需要所有差异,我只需要行之间的差异具有相同的“行索引”。文件 1 中的第 1 行,文件 2 中的第 1 行...文件 1 中的第 2 行,文件 2 中的第 2 行...等等?
  • 在这种情况下,每次从文件fisier.txt 读取新行时,都会打开fisier1.txt。第一个文件中的每一行都将与第二个文件中的每一行进行比较。我不确定这是 TS 想要的。
  • 太酷了!您在纯 shell 中发明了 diff/comm 工具的轻量版。
  • 这种方法与 awk 完美结合!非常感谢!但是你能解释一下为什么当我将你的代码放入我的 shell 时,我变成了错误“意外标记 `3' 附近的语法错误”?
  • Arg 空格太多。固定的。文件描述符编号和&lt;&gt; 字符之间不能有空格。
【解决方案2】:

从你的问题中不清楚你到底想要什么:

  1. 是否需要两个文件中的 5 行不同的行
  2. 是否需要每个文件中的 5 行不同的行

以下示例不是最新的解决方案,而是进一步思考的食物

第一种情况的解决方案——只取差异并打印前 5 行:

comm -3 FILE1 FILE2 | head -n5

第二种情况的解决方案——只取差异并从每个文件中打印 5 行不同的行(总共 10 行):

comm -3 FILE1 FILE2 | head -n10

更新:

上面的示例是在假设FILE1FILE2 都已排序的情况下提出的。如果它们未排序,则需要按如下方式增强这两个示例:

comm -3 <( sort FILE1 ) <( sort FILE2 ) | ...

注意事项:

  1. 其余命令(竖线后面的省略号)相同。
  2. 这是 BASH 方式

【讨论】:

  • 这对我没有帮助,因为我的文件没有排序。它们在每一行都包含单词。我需要将文件 1 中的第 1 行与文件 2 中的第 1 行进行比较,如果它们不同,那么我将显示文件 1 中的第 1 行和文件 2 中的第 1 行,如果它们相等,我将转到下一行。我应该做这件事,直到我有 5 条显示线。
  • 当您发表评论时,我已经更新了我的答案。请阅读答案的更新版本。更新仅反映排序问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-16
  • 1970-01-01
  • 2021-10-07
  • 1970-01-01
  • 2017-04-27
相关资源
最近更新 更多