【问题标题】:How do I compare file names in two directories in shell script?如何在 shell 脚本中比较两个目录中的文件名?
【发布时间】:2017-08-25 01:02:28
【问题描述】:

现在,我的代码如下所示:

#!/bin/bash

Dir1=$1
Dir2=$2

for file1 in $Dir1/*; do
    for file2 in $Dir2/*; do
        if [[ $file1 == $file2 ]]; then
            echo "$file1 is contained in both directories"
        fi
    done
done

我正在尝试比较输入的两个目录的文件名,如果文件名匹配,则说该文件位于两个目录中。 但是,当我尝试运行它时,即使我在两个目录中都有相同的文件,也没有任何内容被回显。

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    Dir1Dir2 中的文件:

    find "$Dir1/" "$Dir2/" -printf '%P\n' | sort | uniq -d
    

    Dir1 中但不在Dir2 中的文件:

    find "$Dir1/" "$Dir2/" "$Dir2/" -printf '%P\n' | sort | uniq -u
    

    Dir2 中但不在Dir1 中的文件:

    find "$Dir1/" "$Dir1/" "$Dir2/" -printf '%P\n' | sort | uniq -u
    

    【讨论】:

    • 这是一个非常优雅的解决方案,因为它的简单逻辑是将其中一个目录中的所有文件打印两次,然后对它们进行排序,以便稍后被 uniq 过滤。找不到有关 printf 的 %P 的文档,如果您能分享一个链接会有所帮助吗?
    • @AnirtakVarma,谢谢。抱歉直到现在才看到你的评论。 find 的手册页将其覆盖在 -printf 部分下。它说:%P File's name with the name of the command line argument under which it was found removed
    • 我有一个特殊情况,我想比较 Dir1 和 Dir2,但 Dir2 是 Dir1 的子文件夹。在那种情况下,我需要在 Dir1 中排除 Dir2 的输出。这是我用来查找位于 Dir1 但不在 Dir2 中的文件的内容:(find . -printf '%P\n' | grep -v Dir2 && find Dir2/ -printf '%P\n' && find Dir2/ -printf '%P\n') | sort | uniq -u 它假定我已经在 Dir1 中。
    【解决方案2】:

    如果您想知道两个目录的共同点,那么这是另一种编码更少的方法。

    #!/bin/bash
    
    comm -12 <(ls -F $1) <(ls -F $2)
    

    有关comm 实用程序的更多信息,请参阅man comm

    【讨论】:

    • 我打算用find而不是ls发布类似的答案。但是如果没有需要比较的子目录,这种方法也应该有效。如需进一步微调,您可以考虑将-F 标志添加到ls..
    • 如果文件名包含换行符,此方法将失败(或至少不清楚)。尝试在两个目录中运行 touch red blue red$'\n'white 并进行比较。
    • @ghoti,我刚刚用你的touch 命令进行了测试,它仍然可以使用包含换行符的文件名,所以我不确定你为什么说这种方法失败了。你真的自己测试过吗?
    • @anishsane,是的,使用find 有其优势,但是由于 OP 没有提及或编码递归,我选择保持简单。
    • @ghoti 的评论是正确的。不鼓励parsing ls(或find)。
    【解决方案3】:

    它不起作用,因为您正在比较包含目录前缀的变量。在比较之前删除前缀:

    name1=${file1##*/}
    name2=${file2##*/}
    if [[ $name1 == $name2 ]]; then
        echo "$name1 exists in both directories"
    fi
    

    此外,嵌套循环似乎是一种低效的方法。您只需要从一个目录中获取文件名,然后对另一个目录使用简单的文件存在性检查。

    for file in $Dir1/*; do
        name=${file##*/}
        if [[ -f $Dir2/$name ]]; then
            echo "$name exists in both directories"
        fi
    done
    

    【讨论】:

      【解决方案4】:

      我刚刚对此进行了测试,它确实有效:

      DIR1=$(ls dir1)
      DIR2=$(ls dir2)
      
      for i in $DIR1; do
          for j in $DIR2; do
              if [[ $i == $j ]]; then
                  echo "$i == $j"
              fi
          done
      done
      

      【讨论】:

      • 对带有特殊字符的文件名失败。详细解释请见ParsingLs
      【解决方案5】:

      您的比较失败,因为Dir1/fooDir2/foo 不同。相反,如果您切换到一个目录,您的 * 将扩展为仅文件名:

      #!/bin/bash
      
      Dir1="$1"
      Dir2="$2"
      
      if ! cd "$Dir1"; then
        echo "ERROR: Couldn't find directory $Dir1" >&2
        exit 1
      fi
      
      if [[ ! "$Dir2" =~ ^/ ]]; then
        echo "ERROR: Second directory must be a full path." >&2
        exit 1
      fi
      
      for file1 in *; do
          if [ -f "$Dir2/$file1" ]; then
              echo "$file1 is contained in both directories"
          fi
      done
      

      请注意,这仅匹配文件 names。如果你想确保它真的是同一个文件,你应该使用cmp来比较它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-28
        • 1970-01-01
        • 2011-02-15
        • 2016-03-02
        • 1970-01-01
        相关资源
        最近更新 更多