Antworten:
Wenn Sie GNU-Dienstprogramme (oder zumindest einen Satz, der mit Zeilen mit Nullterminierung umgehen kann) zur Verfügung haben, bietet eine andere Antwort eine großartige Methode:
find . -maxdepth 1 -print0 | sort -z | uniq -diz
Hinweis: Die Ausgabe enthält nullterminierte Zeichenfolgen. Das Tool, das Sie für die weitere Verarbeitung verwenden, sollte in der Lage sein, damit umzugehen.
In Ermangelung von Tools, die sich mit Zeilen mit Nullterminierung befassen, oder wenn Sie sicherstellen möchten, dass Ihr Code in Umgebungen funktioniert, in denen solche Tools nicht verfügbar sind, benötigen Sie ein kleines Skript:
#!/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
Was ist das für ein Wahnsinn? In dieser Antwort finden Sie eine Erklärung der Techniken, die dies für verrückte Dateinamen sicher machen.
-mindepth
?
find
. Ich habe die Antwort so bearbeitet, dass sie eine Nicht-GNU-Lösung enthält.
Es gibt viele komplizierte Antworten, dies scheint einfacher und schneller zu sein als alle:
find . -maxdepth 1 | sort -f | uniq -di
Wenn Sie doppelte Dateinamen in Unterverzeichnissen finden möchten, müssen Sie nur den Dateinamen und nicht den gesamten Pfad vergleichen:
find . -maxdepth 2 -printf "%f\n" | sort -f | uniq -di
Edit: Shawn J. Goff hat darauf hingewiesen, dass dies fehlschlagen wird, wenn Sie Dateinamen mit Zeilenumbrüchen haben. Wenn Sie GNU-Dienstprogramme verwenden, können Sie diese auch zum Laufen bringen:
find . -maxdepth 1 -print0 | sort -fz | uniq -diz
Die Optionen -print0
(for find) und -z
(for sort and uniq) bewirken, dass sie mit NUL-terminierten Zeichenfolgen anstatt mit Newline-terminierten Zeichenfolgen arbeiten. Da Dateinamen nicht NUL enthalten dürfen, funktioniert dies für alle Dateinamen.
Sortieren Sie die Liste der Dateinamen unabhängig von Groß- und Kleinschreibung und drucken Sie Duplikate. sort
hat eine Option für die Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung. Genauso wie GNU uniq
, aber keine anderen Implementierungen, und alles, was Sie tun können, uniq
ist, jedes Element in einer Reihe von Duplikaten zu drucken, mit Ausnahme des ersten, das angetroffen wird. Unter der Annahme, dass kein Dateiname eine neue Zeile enthält, gibt es mit GNU-Werkzeugen eine einfache Möglichkeit, alle Elemente außer einem in jedem Satz von Duplikaten auszudrucken:
for x in *; do printf "%s\n" "$x"; done |
sort -f |
uniq -id
Portabel, um alle Elemente in jedem Satz von Duplikaten zu drucken, vorausgesetzt, kein Dateiname enthält eine neue Zeile:
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 }'
Wenn Sie Dateinamen mit Zeilenumbrüchen aufnehmen müssen, wählen Sie Perl oder Python. Beachten Sie, dass Sie möglicherweise die Ausgabe optimieren oder die weitere Verarbeitung in derselben Sprache durchführen müssen, da der folgende Beispielcode Zeilenumbrüche verwendet, um Namen in der eigenen Ausgabe zu trennen.
perl -e '
foreach (glob("*")) {push @{$f{lc($_)}}, $_}
foreach (keys %f) {@names = @{$f{$_}}; if (@names > 1) {print "$_\n" foreach @names}}
'
Hier ist eine reine zsh-Lösung. Es ist etwas ausführlich, da es keine integrierte Möglichkeit gibt, die doppelten Elemente in einem Array oder Glob-Ergebnis zu speichern.
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
Ohne GNU find
:
LANG=en_US ls | tr '[A-Z]' '[a-z]' | uniq -c | awk '$1 >= 2 {print $2}'
tr
Es ist sehr wahrscheinlich, dass jeder Zeichensatz, der mehr als ein einziges Byte pro Zeichen verwendet, Schaden anrichtet. Nur die ersten 256 Zeichen von UTF-8 sind bei der Verwendung sicher tr
. Aus Wikipedia tr (Unix) . Die meisten Versionen von tr
, einschließlich GNU tr
und klassischem Unix tr
, arbeiten mit SINGLE BYTES und sind nicht Unicode-kompatibel.
uniq
hat ein Flag i, das die Groß- und Kleinschreibung nicht berücksichtigt.
Ich habe es endlich so geschafft:
find . | tr '[:upper:]' '[:lower:]' | sort | uniq -d
Ich habe find
anstelle von ls
weil ich brauchte den vollständigen Pfad (viele Unterverzeichnisse) enthalten. Ich habe nicht gefunden, wie ich das machen soll ls
.
sort
und uniq
haben jeweils die Groß- und Kleinschreibung f und i ignoriert.
Für alle anderen, die dann eine der Dateien usw. umbenennen möchten:
find . -maxdepth 1 | sort -f | uniq -di | while read f; do echo mv "$f" "${f/.txt/_.txt}"; done