是否有一些工具可以在一个目录中查找文件,但不能在另一个目录中查找文件?

是否有一些工具可以在一个目录中查找文件,但不能在另一个目录中查找文件?

我想编写一个 bash 脚本来在一个目录中查找这些文件,但不在另一个目录中查找这些文件。

下面的脚本可以工作吗?什么时候不呢?

for i in "$1"/*; do
    f=$(basename $i);
    if [ ! -e "$2"/"$f" ]
    then
        echo $f
    fi
done

我听说diff 也可以找到两个目录内容之间的差异。它也能解决同样的任务吗?

或者其他一些工具?

谢谢。

答案1

是的,您可以用于diff此目的。很简单:

diff -rq dir1 dir2

-r选项diff也告诉我们递归到子目录。该-q选项指示diff仅在文件不同时报告。

dir1当我想找出哪些文件在 中,但不在 中dir2,反之亦然时,我通常使用这两个选项。 (-r如果您不想递归到子目录,但只考虑两个目录的直接内容,也可以删除该参数。)

请注意,这将显示存在于dir1但不存在于 中的文件dir2,以及存在于 中dir2但不存在于 中的文件dir1,例如:

$ diff -rq /tmp/dir1/ /tmp/dir2/
Only in /tmp/dir1/: file1
Only in /tmp/dir2/: file2
Only in /tmp/dir2/: file3

如果您只需要其中一个方向(例如,位于dir1但不在 中的文件dir2)并仅获取文件名列表(没有“仅在...”混乱),您当然可以尝试使用来按摩diff的输出grep、等,但在这种情况下,您最好一开始就不要使用sed,而使用 Stéphane Chazelas 的解决方案。awkdiff

答案2

如果您的文件名不包含换行符,您可以执行以下操作:

(export LC_ALL=C; comm -23 <(ls -A dir1) <(ls -A dir2))

找出 中的哪些文件dir1在 中找不到dir2

对于任意文件名,您可以使用数组减法功能zsh

dir1_files=(dir1/*(DN:t)) dir2_files=(dir2/*(DN:t))
dir1_and_not_dir2_files=(${dir1_files:|dir2_files})

(更改***/*递归文件列表)

或者使用 bash4.4+ 和最新版本的 GNU 实用程序:

readarray -td '' dir1_and_not_dir2_files < <(
  export LC_ALL=C
  shopt -s nullglob  dotglob
  comm -z23 <(printf '%s\0' dir1/* | cut -zd/ -f2-) \
            <(printf '%s\0' dir2/* | cut -zd/ -f2-)
)

(使用globstar选项并替换***递归列表)。

需要它LC_ALL=C至少有两个原因:

  • 文件名可以包含任何字节序列(0 或(基于 ASCII 的系统上的 0x2F)的值除外/),而comm文本实用程序,因此对于那些不格式化有效字符的字节序列未指定行为。在 C 语言环境中,所有字符都是单字节且所有字节都是有效字符(尽管可能未定义),sp 任何文件名都是有效文本(还考虑到最大文件名长度通常明显小于最大文本行长度) 。

  • 更重要的是,comm需要排序的输入,但在某些语言环境中,某些字符具有未定义的排序顺序或与其他字符排序相同,这会造成混淆comm。例如,在 en_GB.UTF-8 语言环境的 GNU 系统上:

      $ ls dir1 dir2
      dir1:
      

相关内容