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

Bash shell scripting check while comparing 2 files

我有 2 个文件

文件 1

abc

cde

efg

hij

jkl

文件 2

abc

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

efg

(*) hij -- without braces

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

现在,逐行比较两个文件,即file1的第一行只与file2的第一行进行比较

abc ---- abc

cde ---- * * * 

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

然而,在比较时

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

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

我已经为相同的比较 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 < "" 3<""

您的脚本已经正确处理了单星号和双星号的情况。回想一下,您的脚本假定 diff=1,并且只有在找到匹配项时才更改为 diff=0。 ${b[@]} 中仅由一个星号组成的元素与来自 file1 的输入行比较不相等,这意味着这些元素正确地保留了原始假设 (diff=1) 不变。但是,如果来自 file1 的输入行只包含一个星号,则比较将导致匹配并设置 diff=0。但是 file2 中单个星号的含义会变得有些模棱两可;它是指 "match a literal single-asterisk line from file1",还是 "don't match any line from file1"?后一种感觉似乎是您希望 file2 中的星号表示的意思。如果您希望在这种奇怪的情况下保留这种感觉,则必须添加一个显式测试以跳​​过文件 2 中的星号词:

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

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

关于三星号的情况,听起来您想完全跳过该情况。如上所述,当前来自 file2 的单星号元素被隐式跳过(因为它们不匹配来自 file1 的任何输入行),这使得 diff=1,并导致打印 * * * 消息。为了防止这种情况,您可以添加一个明确的保护措施来防止 * * *,如下所示:

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

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

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

参见 bash 手册,"Parameter expansion"。

如果您不希望输出中出现星号,则必须将 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 < "" 3<""

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