Risposte:
Se hai utility GNU (o almeno un set che può gestire linee a terminazione zero), un'altra risposta ha un ottimo metodo:
find . -maxdepth 1 -print0 | sort -z | uniq -diz
Nota: l'output avrà stringhe con terminazione zero; lo strumento che usi per elaborare ulteriormente dovrebbe essere in grado di gestirlo.
In assenza di strumenti che si occupano di linee a terminazione zero, o se si desidera assicurarsi che il codice funzioni in ambienti in cui tali strumenti non sono disponibili, è necessario un piccolo script:
#!/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
Cos'è questa follia? Vedi questa risposta per una spiegazione delle tecniche che lo rendono sicuro per i nomi di file folli.
-mindepth
?
find
; Ho modificato la risposta per includere una soluzione non GNU.
Ci sono molte risposte complicate sopra, questa sembra più semplice e veloce di tutte:
find . -maxdepth 1 | sort -f | uniq -di
Se vuoi trovare nomi di file duplicati nelle sottodirectory, devi confrontare solo il nome del file, non l'intero percorso:
find . -maxdepth 2 -printf "%f\n" | sort -f | uniq -di
Modifica: Shawn J. Goff ha sottolineato che ciò fallirà se si hanno nomi di file con caratteri di nuova riga. Se stai usando le utility GNU, puoi far funzionare anche queste:
find . -maxdepth 1 -print0 | sort -fz | uniq -diz
L' opzione -print0
(per trovare) e l' -z
opzione (per ordinare e uniq) fanno sì che funzionino su stringhe con terminazione NUL, anziché su stringhe con fine riga. Poiché i nomi dei file non possono contenere NUL, questo funziona per tutti i nomi di file.
Ordina l'elenco dei nomi dei file in modo insensibile alle maiuscole e stampa i duplicati. sort
ha un'opzione per l'ordinamento senza distinzione tra maiuscole e minuscole. Lo stesso vale per GNU uniq
, ma non per altre implementazioni, e tutto ciò che puoi fare uniq
è stampare ogni elemento in una serie di duplicati tranne il primo che si incontra. Con gli strumenti GNU, supponendo che nessun nome di file contenga una nuova riga, esiste un modo semplice per stampare tutti gli elementi tranne uno in ciascun set di duplicati:
for x in *; do printf "%s\n" "$x"; done |
sort -f |
uniq -id
Portabilmente, per stampare tutti gli elementi in ogni set di duplicati, supponendo che nessun nome di file contenga una nuova riga:
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 }'
Se devi inserire nomi di file contenenti newline, scegli Perl o Python. Si noti che potrebbe essere necessario modificare l'output, o meglio eseguire l'ulteriore elaborazione nella stessa lingua, poiché il codice di esempio riportato di seguito utilizza le nuove righe per separare i nomi nel proprio output.
perl -e '
foreach (glob("*")) {push @{$f{lc($_)}}, $_}
foreach (keys %f) {@names = @{$f{$_}}; if (@names > 1) {print "$_\n" foreach @names}}
'
Ecco una soluzione zsh pura. È un po 'prolisso, in quanto non esiste un modo integrato per mantenere gli elementi duplicati in un risultato array o glob.
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
Senza GNU find
:
LANG=en_US ls | tr '[A-Z]' '[a-z]' | uniq -c | awk '$1 >= 2 {print $2}'
tr
è molto probabile che causi il caos su qualsiasi set di caratteri che utilizza più di un singolo byte per carattere. Solo i primi 256 caratteri di UTF-8 sono sicuri durante l'utilizzo tr
. Da Wikipedia tr (Unix) .. La maggior parte delle versioni di tr
, incluso GNU tr
e Unix classico tr
, funzionano su SINGOLI BYTES e non sono conformi a Unicode ..
uniq
ha una bandierina senza distinzione tra maiuscole e minuscole i.
Finalmente sono riuscito in questo modo:
find . | tr '[:upper:]' '[:lower:]' | sort | uniq -d
Ho usato find
invece di ls
causa avevo bisogno del percorso completo (molte sottodirectory) incluso. Non ho trovato il modo di farlo ls
.
sort
e uniq
hanno flag di maiuscole / minuscole, rispettivamente f e i.
Per chiunque voglia quindi rinominare ecc. Uno dei file:
find . -maxdepth 1 | sort -f | uniq -di | while read f; do echo mv "$f" "${f/.txt/_.txt}"; done