我需要找到一个给定的目录树中的每个副本的文件名。 我不知道,什么DIR树的用户会给作为脚本参数,所以我不知道的目录层次结构。 我尝试这样做:
#!/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 "
但它doenst工作对我来说,不知道为什么。 即使我有一个重复,不打印输出。 我使用的是Xubuntu 12.04。
Answer 1:
下面是另一种解决方案(基于建议通过@吉姆-麦克纳马拉),而不AWK:
解决方法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(以临时文件)
#!/bin/sh
dirname=/path/to/directory
tempfile=myTempfileName
find $dirname -type f > $tempfile
cat $tempfile | sed 's_.*/__' | sort | uniq -d|
while read fileName
do
grep "$fileName" $tempfile
done
#rm -f tempfile
既然你可能不希望写在某些情况下,硬盘的临时文件,你可以选择适合您需求的方法。 这两个例子打印出来的文件的完整路径。
此奖金的问题:是否有可能find命令的输出整体保存为一个列表给一个变量?
Answer 2:
#!/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}}}
Answer 3:
是的,这是一个非常古老的问题。 但是,所有这些循环和临时文件似乎有点麻烦。
这是我的1行的答案:
find /PATH/TO/FILES -type f -printf '%p/ %f\n' | sort -k2 | uniq -f1 --all-repeated=separate
它有它的原因的限制uniq
和sort
:
- 在文件名中没有空格(空格,制表)(将被解释为新领域
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
。
Answer 4:
#!/bin/bash
file=`mktemp /tmp/duplicates.XXXXX` || { echo "Error creating tmp file"; exit 1; }
find $1 -type f |sort > $file
awk -F/ '{print tolower($NF)}' $file |
uniq -c|
awk '$1>1 { sub(/^[[:space:]]+[[:digit:]]+[[:space:]]+/,""); print }'|
while read line;
do grep -i "$line" $file;
done
rm $file
它也与文件名中的空间工作。 这里有一个简单的测试(第一个参数就是目录):
./duplicates.sh ./test
./test/2/INC 255286
./test/INC 255286
Answer 5:
一个“查找”命令仅:
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
Answer 6:
该解决方案写一个临时文件到一个临时目录中找到的每个文件名唯一。 在临时文件,我写的,我第一次发现的唯一的文件名,路径,这样以后可以输出。 所以,我创造了很多文件等发布的解决方案。 但是,这是我能理解。
以下是脚本,命名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
:与击版本测试GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Answer 7:
这里是我的贡献(这只是搜索一个特定的文件类型,在这种情况下,PDF文件),但它这样做递归:
#!/usr/bin/env bash
find . -type f | while read filename; do
filename=$(basename -- "$filename")
extension="${filename##*.}"
if [[ $extension == "pdf" ]]; then
fileNameCount=`find . -iname "$filename" | wc -l`
if [[ $fileNameCount -gt 1 ]]; then
echo "File Name: $filename, count: $fileNameCount"
fi
fi
done
文章来源: How to find duplicate filenames (recursively) in a given directory? BASH