我有办法找到目录中具有重复文件名的所有文件,无论大小写(大写和/或小写)如何?
答案1
如果您有可用的 GNU 实用程序(或至少有一组可以处理以零结尾的行),另一个答案有一个很棒的方法:
find . -maxdepth 1 -print0 | sort -z | uniq -diz
注意:输出将具有以零结尾的字符串;您用来进一步处理它的工具应该能够处理这个问题。
如果没有处理零终止行的工具,或者如果您想确保代码在此类工具不可用的环境中工作,则需要一个小脚本:
#!/bin/sh
for f in *; do
find . -maxdepth 1 -iname ./"$f" -exec echo \; | wc -l | while read count; do
[ $count -gt 1 ] && echo $f
done
done
这是什么疯狂?看这个答案有关使疯狂文件名安全的技术的解释。
答案2
上面有很多复杂的答案,这似乎比所有这些都更简单、更快:
find . -maxdepth 1 | sort -f | uniq -di
如果您想在子目录中查找重复的文件名,那么您需要仅比较文件名,而不是整个路径:
find . -maxdepth 2 -printf "%f\n" | sort -f | uniq -di
编辑:Shawn J. Goff 指出,如果文件名带有换行符,这将会失败。如果您使用 GNU 实用程序,您也可以使这些工作:
find . -maxdepth 1 -print0 | sort -fz | uniq -diz
-print0
(用于查找)和选项-z
(用于排序和 uniq)使它们适用于 NUL 终止的字符串,而不是换行符终止的字符串。由于文件名不能包含 NUL,因此这适用于所有文件名。
答案3
以不区分大小写的方式对文件名列表进行排序并打印重复项。sort
有一个不区分大小写的排序选项。 GNU 也是如此uniq
,但其他实现则不然,您所能做的uniq
就是打印一组重复项中的每个元素,除了遇到的第一个元素之外。使用 GNU 工具,假设没有文件名包含换行符,有一种简单的方法可以打印除每组重复项中的一个之外的所有元素:
for x in *; do printf "%s\n" "$x"; done |
sort -f |
uniq -id
可移植地,要打印每组重复项中的所有元素,假设没有文件名包含换行符:
for x in *; do printf "%s\n" "$x"; done |
sort -f |
awk '
tolower($0) == tolower(prev) {
print prev;
while (tolower($0) == tolower(prev)) {print; getline}
}
1 { prev = $0 }'
如果您需要容纳包含换行符的文件名,请使用 Perl 或 Python。请注意,您可能需要调整输出,或者更好地使用相同的语言进行进一步处理,因为下面的示例代码使用换行符来分隔其输出中的名称。
perl -e '
foreach (glob("*")) {push @{$f{lc($_)}}, $_}
foreach (keys %f) {@names = @{$f{$_}}; if (@names > 1) {print "$_\n" foreach @names}}
'
这是一个纯粹的 zsh 解决方案。这有点冗长,因为没有内置方法可以将重复元素保留在数组或全局结果中。
a=(*)(N); a=("${(@io)a}")
[[ $#a -le 1 ]] ||
for i in {2..$#a}; do
if [[ ${(L)a[$i]} == ${(L)a[$((i-1))]} ]]; then
[[ ${(L)a[$i-2]} == ${(L)a[$((i-1))]} ]] || print -r $a[$((i-1))]
print -r $a[$i]
fi
done
答案4
没有 GNU find
:
LANG=en_US ls | tr '[A-Z]' '[a-z]' | uniq -c | awk '$1 >= 2 {print $2}'