Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 如何在给定目录中查找重复的文件名(递归)?猛击_Bash_Duplicates_Filenames - Fatal编程技术网

Bash 如何在给定目录中查找重复的文件名(递归)?猛击

Bash 如何在给定目录中查找重复的文件名(递归)?猛击,bash,duplicates,filenames,Bash,Duplicates,Filenames,我需要在给定的目录树中找到每个重复的文件名。我不知道,dir-tree用户将给出什么作为脚本参数,所以我不知道目录层次结构。我试过这个: #!/bin/sh find -type f | while IFS= read vo do echo `basename "$vo"` done 但那不是我真正想要的。它只找到一个重复文件,然后结束,即使有更多重复的文件名,它也不会打印整个路径(只打印一个文件名)和重复计数。我想执行类似于此命令的操作: find DIRNAME | tr '[A-Z]'

我需要在给定的目录树中找到每个重复的文件名。我不知道,dir-tree用户将给出什么作为脚本参数,所以我不知道目录层次结构。我试过这个:

#!/bin/sh
find -type f | while IFS= read vo
do
echo `basename "$vo"`
done
但那不是我真正想要的。它只找到一个重复文件,然后结束,即使有更多重复的文件名,它也不会打印整个路径(只打印一个文件名)和重复计数。我想执行类似于此命令的操作:

find DIRNAME | tr '[A-Z]' '[a-z]' | sort | uniq -c | grep -v " 1 " 
但这对我不起作用,不知道为什么。即使我有一个副本,它也不会打印任何东西。 我使用Xubuntu 12.04

#!/bin/sh
dirname=/path/to/check
find $dirname -type f | 
while read vo
do
  echo `basename "$vo"`
done | awk '{arr[$0]++; next} END{for (i in arr){if(arr[i]>1){print i}}}  
它还可以处理文件名中的空格。下面是一个简单的测试(第一个参数是目录):

以下是另一个没有awk的解决方案(基于@jim mcnamara的建议):

解决方案1

#!/bin/sh 
dirname=/path/to/directory
find $dirname -type f | sed 's_.*/__' | sort|  uniq -d| 
while read fileName
do
find $dirname -type f | grep "$fileName"
done
但是,您必须执行两次相同的搜索。如果您必须搜索大量数据,这可能会变得非常缓慢。将“查找”结果保存在临时文件中可能会提供更好的性能

解决方案2(带临时文件)

由于在某些情况下,您可能不希望在硬盘上写入临时文件,因此可以选择适合您需要的方法。 这两个示例都打印出文件的完整路径


这里有一个额外的问题:是否可以将find命令的整个输出保存为变量的列表

此解决方案为找到的每个唯一文件名将一个临时文件写入临时目录。在临时文件中,我写下我第一次找到唯一文件名的路径,以便以后可以输出它。因此,我创建了比其他发布的解决方案多得多的文件。但是,这是我能理解的

下面是名为
fndupe
的脚本

#!/bin/bash

# Create a temp directory to contain placeholder files.
tmp_dir=`mktemp -d`

# Get paths of files to test from standard input.
while read p; do
  fname=$(basename "$p")
  tmp_path=$tmp_dir/$fname
  if [[ -e $tmp_path ]]; then
    q=`cat "$tmp_path"`
    echo "duplicate: $p"
    echo "    first: $q"
  else
    echo $p > "$tmp_path" 
  fi
done

exit
下面是使用该脚本的示例

$ find . -name '*.tif' | fndupe
下面是脚本发现重复文件名时的输出示例

duplicate: a/b/extra/gobble.tif
    first: a/b/gobble.tif
使用Bash版本进行测试:
gnubash,版本4.1.2(1)-发行版(x86\u 64-redhat-linux-GNU)
仅一个“查找”命令:

lst=$( find . -type f )
echo "$lst" | rev | cut -f 1 -d/ | rev | sort -f | uniq -i | while read f; do
   names=$( echo "$lst" | grep -i -- "/$f$" )
   n=$( echo "$names" | wc -l )
   [ $n -gt 1 ] && echo -e "Duplicates found ($n):\n$names"
done

是的,这是一个很老的问题。 但所有这些循环和临时文件似乎都有点麻烦

以下是我的单线答案: 由于
uniq
sort

find  /PATH/TO/FILES -type f -printf 'size: %s bytes, modified at: %t, path: %h/, file name: %f\n' | sort -k15 | uniq -f14 --all-repeated=prepend
  • 文件名中没有空格(空格、制表符)(将被
    uniq
    sort
    解释为新字段)
  • 需要将文件名打印为以空格分隔的最后一个字段(
    uniq
    不支持仅比较1个字段,并且不能灵活使用字段分隔符)
但是由于
find-printf
,它的输出非常灵活,对我来说效果很好。这似乎也是@yak最初想要达到的

演示您的一些选项:

find  /PATH/TO/FILES -type f -printf 'size: %s bytes, modified at: %t, path: %h/, file name: %f\n' | sort -k15 | uniq -f14 --all-repeated=prepend
sort
uniq
中还有忽略大小写的选项(正如主题开场白打算通过管道通过
tr
实现的那样)。使用
man uniq
man sort

查找它们这是我的贡献(在本例中,这只是搜索特定的文件类型,即PDF),但它以递归方式执行此操作:

#/usr/bin/env bash
找到-读取文件名时键入f |;做
文件名=$(基本名称--“$filename”)
extension=“${filename##*.}”
如果[[$extension==“pdf”];然后
filenamecont=`find-iname“$filename”| wc-l`
如果[$filenamecont-gt 1]];然后
echo“文件名:$filename,计数:$filenamecont”
fi
fi
完成

是否可以在没有awk的情况下制作?无论如何,谢谢:)您可以用任何支持关联数组的语言(或者哈希是另一个名称)来实现这一点——perl就是一个例子。Bash4也支持关联数组。所以你说只有bash解决方案是不可能的?我的意思是,没有sed、awk、perl、python等等。只是纯bash?顺便说一下,这个解决方案只告诉您文件名,而不告诉它们所在的路径。我还以为那是一个requirement@ElisianoPetrini:哦,谢谢,你说得对。我需要一条完整的路径。问题又来了。您可以使用grep-f来摆脱while并将其简化一点:cat$tempfile | sed's |.*/| | | sort | uniq-d | grep-f$tempfile解决方案1中的小错误可能会导致误报。您最好将最后一个查找写为:find$dirname-type f | grep“^${fileName}$”如何更改解决方案2以使找到的第一个文件不添加到临时文件中,只有第二个找到的副本?MacOs:find:-printf:unknown primary或operator
/usr/share/fslint/fslint/findsn/path/to/files
,但我更喜欢您的单行程序,因为它具有灵活性。
lst=$( find . -type f )
echo "$lst" | rev | cut -f 1 -d/ | rev | sort -f | uniq -i | while read f; do
   names=$( echo "$lst" | grep -i -- "/$f$" )
   n=$( echo "$names" | wc -l )
   [ $n -gt 1 ] && echo -e "Duplicates found ($n):\n$names"
done
find /PATH/TO/FILES -type f -printf '%p/ %f\n' | sort -k2 | uniq -f1 --all-repeated=separate
find  /PATH/TO/FILES -type f -printf 'size: %s bytes, modified at: %t, path: %h/, file name: %f\n' | sort -k15 | uniq -f14 --all-repeated=prepend