如何使用 bash comm 获取目录 A 而不是 B 中的文件,反之亦然?

How to get files in directory A but not B and vice versa using bash comm?

我正在尝试使用 comm 获取文件夹 A 中不在 B 中的文件,反之亦然:

comm -3 <(find /Users/rob/A -type f -exec basename {} ';' | sort) <(find "/Users/rob/B" -type f -exec basename {} ';' | sort)

我正在使用 basename {} ';' 来排除目录路径,但这是我得到的输出:

    IMG_5591.JPG
IMG_5591.jpeg
    IMG_5592.JPG
IMG_5592.jpeg
    IMG_5593.JPG
IMG_5593.jpeg
    IMG_5594.JPG
IMG_5594.jpeg

第一个目录的名称中有一个选项卡,因此所有条目都被认为是不同的。我做错了什么?

前导标签 不是 find|basename 代码生成;前导标签由 comm ...

生成

comm 根据输入标志生成 1 到 3 列输出;第 2 列输出将有一个前导制表符,而第 3 列输出将有 2 个前导制表符。

在这种情况下,OP 的代码表示要忽略第 3 列(-3,两个来源之间共有的文件),因此 comm 生成 2 列输出,其中第 2 列具有前导标签。

一个简单的修复:

comm --output-delimiter="" <(find...|sort...) <(find...|sort...)

如果由于某种原因您的 comm 不支持 --output-delimiter 标志:

comm <(find...|sort...) <(find...|sort...) | tr -d '\t'

这假定文件名不包含嵌入的制表符,否则将 tr 替换为您喜欢的代码以去除前导白色 space,例如:

comm <(find...|sort...) <(find...|sort...) | sed 's/^[[:space:]]*//'

演示 ...

$ cat file1
a.txt
b.txt

$ cat file2
b.txt
c.txt

$ comm file1 file2
a.txt
                b.txt
        c.txt

# 2x tabs (\t) before 'b.txt' (3rd column), 1x tab (\t) before 'c.txt' (2nd column):

$ comm file1 file2 | od -c
0000000   a   .   t   x   t  \n  \t  \t   b   .   t   x   t  \n  \t   c
0000020   .   t   x   t  \n

# OP's scenario:

$ comm -3 file1 file2
a.txt
        c.txt

# 1x tab (\t) before 'c.txt' (2nd column):

$ comm -3 file1 file2 | od -c
0000000   a   .   t   x   t  \n  \t   c   .   t   x   t  \n

删除前导标签:

$ comm --output-delimiter="" -3 file1 file2
a.txt
c.txt

$ comm -3 file1 file2 | tr -d '\t'
a.txt
c.txt

$ comm -3 file1 file2 | sed 's/^[[:space:]]*//'
a.txt
c.txt

如果 basename 导致问题,您可以使用 find 的 printf :

#!/bin/bash
    
find_basename(){
    find "" -type f -printf "%P\n" | sort
}

comm -3 <(find_basename /Users/rob/A) <(find_basename /Users/rob/B)