Answers:
如果您有可用的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
这是什么疯狂?有关使疯狂文件名安全的技术的说明,请参见此答案。
-mindepth
吗?
find
;我已经编辑了答案,以包括非GNU解决方案。
上面有很多复杂的答案,这似乎比所有答案都简单和快捷:
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
选项(sort和uniq)导致他们对NULL结尾的字符串的工作,而不是换行终止字符串。由于文件名不能包含NUL,因此这适用于所有文件名。
以不区分大小写的方式对文件名列表进行排序并打印重复项。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
没有GNU find
:
LANG=en_US ls | tr '[A-Z]' '[a-z]' | uniq -c | awk '$1 >= 2 {print $2}'
tr
是非常有可能肆虐上使用比每个字符一个字节以上的任何字符集。使用时,只有UTF-8的前256个字符是安全的tr
。从维基百科TR(UNIX) .. 大多数版本的tr
,包括GNU tr
和经典的Unix tr
,运行在单字节,并且不支持Unicode标准..
uniq
具有不区分大小写的标志i。