如何运行短文件名的差异?

如何运行短文件名的差异?

我正在使用 bash shell。我想查看两个目录中文件名的差异,但仅限于这些目录的直接子目录。例如,如果我有这些目录,其中子文件/目录名为 ...

dir1
-> abc
-> def
-> ghi

dir2
-> abc
-> fff
-> ghi

我希望能够运行一些命令,告诉我 dir2 有一个名为“fff”的文件/目录,而 dir1 没有,而“dir1”有一个名为“def”的子文件/目录,而 dir2 没有没有。我怎么做?

答案1

for name in dir1/* dir2/*; do
    bname=${name##*/}

    if [ ! -e "dir1/$bname" ]; then
        printf '"%s" not in dir1\n' "$bname"
    elif [ ! -e "dir2/$bname" ]; then
        printf '"%s" not in dir2\n' "$bname"
    fi
done

这将迭代dir1和中的所有名称dir2$bname将是名称的基本名称($name不带路径)。

如果在 中找不到(基本)名称dir1,则会报告此情况。否则,如果在dir2报告中没有找到它。

这可以处理包含嵌入换行符的文件名,并且应该与/bin/sh任何兼容的shshell 一起运行。

这可能会扩展到两个以上的目录。和bash

dirs=( dir1 dir2 dir3 dir4 )

for dir in "${dirs[@]}"; do
    for name in "$dir"/*; do

        bname=${name##*/}

        for tdir in "${dirs[@]}"; do
            if [ ! -e "$tdir/$bname" ]; then
                printf '"%s" not found in %s\n' "$bname" "$tdir"
            fi
        done

    done
done

$ tree
.
|-- dir1
|   `-- filename 1
|-- dir2
|   |-- filename 1
|   |-- filename 3
|   `-- hello
world
`-- script.sh

$ sh script.sh
"filename 3" not in dir1
"hello
world" not in dir1

答案2

为此,我非常喜欢comm -3plainls的输出:

$ comm -3 <(ls dir1) <(ls dir2)
def
        fff

第一列中的条目仅在第一个目录中,第二列中的条目仅在第二个目录中;该-3选项删除第三列,该列显示两者共有的条目。您还可以指定-1仅查看 中存在dir2但不存在的文件dir1,以及-2仅查看 中存在dir1但不存在的文件dir2

为此,您需要确保没有设置任何ls选项通过它的OPTIONS配置或别名。您可以使用诸如以下的变体来避免此类问题

$ comm -z -3 <(cd dir1; printf "%s\0" *) <(cd dir2; printf "%s\0" *) | tr '\0' '\n'
def
        fff

后者避免了文件名中特殊字符的问题。您可以将其与-1或结合起来-2,然后将tr其放入xargs -0其中以进一步处理任一组文件。

相关内容