如何使用 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)
我正在尝试使用 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)