比较2个文件时Bash shell脚本检查

时间:2015-01-19 09:05:55

标签: linux bash shell loops comparison

我有2个文件

档案1

abc

cde

efg

hij

jkl

文件2

abc

( * ) ( * ) ( * ) -- without the braces

efg

(*) hij -- without braces

(*) (*) lmn --- without braces

现在,在逐行比较两个文件的同时,即仅与file2的第一行比较的第一行file1

abc ---- abc

cde ---- * * * 

当遇到* * *时,比较应移至下一行比较其他行

但是,在比较时

hij --- (*) hij  or jkl --- (*) (*) lmn

hij必须与File2的hij进行比较,并且必须正常 并且jkl必须与lmn进行比较,并且必须给出不正确:在任何一种情况下都忽略** *

我已经为相同的2个文件编写了脚本,但我无法检查*

你可以帮我解决同样的问题吗?

比较文件的脚本片段

# 1. Read lines from file1 as string, and file2 as comma-separated array.

while read -r a && IFS=, read -ra b <&3; do
# 2. If both empty lines, continue.

if [[ "$a" == "" && ${#b[@]} == 0 ]]; then

    continue

fi

# 3. Start assuming diff.

diff=1

# 4. Loop fields in $b.

for e in ${b[@]}; do

    # Compare field in $b with $a, if match then abort.

    if [[ "$e" == "$a" ]]; then

        diff=0

        break

    fi

done

# 5. If no match found, print line from $b.

if [[ $diff == 1 ]]; then

    # Join array with <space>comma.

    line=$(printf ", %s" "${b[@]}")

    # Print line, excluding leading <space>comma.

    printf "%s\n" "${line:2}"

fi

# Input argument one as file 1 to stdin, and argument two as file 2 to

# file descriptor 3.

done < "$1" 3<"$2"

2 个答案:

答案 0 :(得分:0)

您的脚本已正确处理单个星号和双星号的情况。回想一下,您的脚本假定diff = 1,并且如果找到匹配,则仅更改为diff = 0。 ${b[@]}只包含一个星号的元素比较不等于file1的输入行,这意味着这些元素正确地保留了原始假设(diff = 1)。但是,如果file1的输入行只包含一个星号,那么比较将导致匹配并设置diff = 0。但是,文件2中单个星号的含义会变得有些含糊不清;它是否意味着“匹配来自file1的文字单星号行”,或者它是否意味着“不匹配来自file1的任何行”?后一种意义似乎是你想要file2中的星号意思。如果您希望在这种奇怪的情况下保留这种意义,则必须添加一个显式测试以跳​​过file2中的星号字:

if [[ "$e" == '*' ]]; then continue; fi;

此测试将在for循环的开始处进行。

关于三重星号的情况,听起来你想完全跳过这种情况。如上所述,目前来自file2的单星号元素被隐式跳过(因为它们与file1中的任何输入行都不匹配),这会留下diff = 1,并导致打印* * *消息。为防止这种情况发生,您可以对* * *添加明确的警示,如下所示:

if [[ ${#b[@]} -eq 3 && "${b[0]}" == '*' && "${b[1]}" == '*' && "${b[2]}" == '*' ]]; then continue; fi;

在空行检查之后,此测试将接近while循环的开始。

答案 1 :(得分:0)

我更喜欢以下解决方案;您可以使用bash参数扩展功能来忽略简化脚本的前导星号。

参见bash手册,&#34;参数扩展&#34;。

如果您不想在输出中使用星号,则必须将if语句中使用的参数扩展的结果分配给单独的变量,并在比较中使用它。

while read -r a && IFS=, read -ra b <&3
do

    # If both lines are empty, continue.
    if [ -z "$a" ] && [ -z "$b" ]
    then
        continue
    fi

    # If b contains three stars, don't compare.
    if [ "$b" == "***" ]
    then
        continue
    fi

    # compare a and b ignoring leading *
    if [ "$a" == "${b##\*}" ]
    then
        echo "$a: ok"
    else
        echo "$a/$b: nok"
    fi
done < "$1" 3<"$2"

此外,我会事先从文件中删除空行并检查两个输入文件的行数,以避免错误不匹配。