【问题标题】:How to get files in directory A but not B and vice versa using bash comm?如何使用bash comm获取目录A而不是B中的文件,反之亦然?
【发布时间】:2021-11-06 18:56:18
【问题描述】:

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

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

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

【问题讨论】:

  • 请用预期的输出更新问题
  • 查看我的答案以了解comm 生成前导标签的解释;请记住,删除选项卡不会改变整体输出,因为文件名确实不同......一组文件名以.JPG结尾,而另一组文件名以.jpeg结尾;最终结果:comm 工作正常...... OP 只需要添加一些代码来删除前导标签

标签: bash find comm


【解决方案1】:

前导标签不是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 替换为您喜欢的代码以去除前导空格,例如:

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

【讨论】:

  • 谢谢。我对这些列感到困惑,尽管它是查找响应的一部分。我希望得到一个空洞的回应 - 我没有注意到扩展名不同;(
  • 顺便问一下,关于如何排除扩展的任何提示?我尝试了来自stackoverflow.com/questions/41965415/… 的东西但没有成功(我没有得到任何输出)。另外,我不能使用 printf。
  • @Roberto 你没有得到什么输出? find 调用没有输出?或者comm 调用没有输出?仅基于提供的示例数据,我希望 comm 调用(无扩展)不会产生任何输出......对吗?
  • 修改find 调用以剥离扩展名是冒险脱离本问答的初衷;如果您仍然无法让新的find 代码正常工作,我建议您创建一个新问题并关注find + remove extensions 问题
【解决方案2】:

如果basename引起问题,可以使用find的printf:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    • 2011-07-13
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    相关资源
    最近更新 更多