找到目录中的所有重复子目录

时间:2016-10-02 00:38:26

标签: bash shell unix recursion

我需要创建一个shell脚本,“在当前工作目录下列出所有相同的子目录(递归)。”

我是shell脚本的新手。我该如何处理?

对我来说,这意味着:

  • 对于从某个起始目录开始的每个目录,将其与按名称共享的每个其他目录进行比较。
    • 如果其他目录具有相同名称,请检查大小。
      • 如果同样大小,也可以逐项递归地比较每个目录的内容,可能是md5sum(?)并继续对目录中的每个子目录进行比例(递归?)
  • 然后,继续在遇到的每个子目录上递归调用它
  • 然后,重复目录结构中的每个其他目录

这本来是我写过的最复杂的程序,所以我假设我只是不知道有一些shell命令要为我做大部分工作?

即,我应该怎样接近这个?所有其他部分都是关于谷歌搜索,直到我发现shell命令为我做了90%。

(对于我以前无法完成的任务,在这部分上取零,需要知道将来如何处理它。)

2 个答案:

答案 0 :(得分:1)

我很惊讶地听到有一个特殊的Unix工具或标准Unix工具的特殊用法来完成您所描述的内容。也许你对任务的理解比任务提供者的意图更复杂。也许与“相同”的东西有关。通常,不允许使用硬链接目录,因此这也许并不意味着。

无论如何,我通过为树中的所有节点创建校验和来实现此任务,即。即递归:

  • 对于目录,记下所有条目及其校验和的名称(递归)并计算它们的校验和,
  • 用于普通文件计算其内容的校验和,
  • 对于符号链接和特殊文件(设备等),请考虑你想要的东西(我会把它留下来)。

为所有元素创建校验和后,搜索重复项(通过对所有元素列表进行排序并搜索连续行)。

快速解决方案可能是这样的:

SELECT VendorState, InvoiceTotal
    FROM Invoices JOIN Vendors ON Invoices.VendorID = Vendors.VendorID
    WHERE VendorState > ALL
        (SELECT COUNT(InvoiceTotal)
        FROM Invoices JOIN Vendors ON Invoices.VendorID = Vendors.VendorID
        WHERE VendorState > 1)

这个脚本使用了两个可能不太清楚的技巧,所以我提到它们:

  • 要将shell函数传递给#!/bin/bash dirchecksum() { if [ -f "$1" ] then checksum=$(md5sum < "$1") elif [ -d "$1" ] then checksum=$( find "$1" -maxdepth 1 -printf "%P " \( ! -path "$1" \) \ -exec bash -c "dirchecksum {}" \; | md5sum ) fi echo "$checksum" echo "$checksum $1" 1>&3 } export -f dirchecksum list=$(dirchecksum "$1" 3>&1 1>/dev/null) lastChecksum='' while read checksum _ path do if [ "$checksum" = "$lastChecksum" ] then echo "duplicate found: $path = $lastPath" fi lastChecksum=$checksum lastPath=$path done < <(sort <<< "$list") ,可以find -exec(在它下面完成),然后调用export -f来执行它。
  • shell函数有两个输出流,一个用于返回结果校验和(这是通过stdout,即fd 1),另一个用于给出在此过程中找到的每个校验和(this是通过fd 3)。

最后的排序使用通过fd 3给出的列表作为输入。

答案 1 :(得分:1)

也许是这样的:

$ find -type d -exec sh -c "echo -n {}\  ; sh -c \"ls -s {}; basename {}\"|md5sum " \; | awk '$2 in a {print "Match:"; print a[$2], $1; next} a[$2]=$1{next}'
Match:
./bar/foo ./foo

find所有目录:find -type d,输出:

.
./bar
./bar/foo
./foo

ls -s {}; basename {}将打印简化的目录列表和列出的目录的基本名称,例如目录fools -s foo; basename foo

total 0
0 test
foo

这些将涵盖每个目录中的文件,它们的大小和目录名称。该输出将发送到md5sum以及dir:

. 674e2573b49826d4e32dfe81d9680369  -
./bar 4c2d588c5fa9781ad63ad8e86e575e01  -
./bar/foo ff8d1569685be86366f18ea89851db35  -
./foo ff8d1569685be86366f18ea89851db35  -

将发送至awk

$2 in a {            # hash as array key
    print "Match:"   # separate hits in output
    print a[$2], $1  # print matching dirscompared to
    next             # next record
} 
a[$2]=$1 {next}      # only first match is stored and 

测试目录结构:

$ mkdir -p test/foo; mkdir -p test/bar/foo; touch test/foo/test; touch test/bar/foo/test
$ find test/
test/
test/bar
test/bar/foo
test/bar/foo/test  # touch test
test/foo
test/foo/test      # touch test