Respuestas:
Si tiene utilidades GNU (o al menos un conjunto que puede manejar líneas terminadas en cero) disponibles, otra respuesta tiene un excelente método:
find . -maxdepth 1 -print0 | sort -z | uniq -diz
Nota: la salida tendrá cadenas terminadas en cero; la herramienta que use para procesarlo más adelante debería poder manejar eso.
En ausencia de herramientas que se ocupen de líneas terminadas en cero, o si desea asegurarse de que su código funcione en entornos donde tales herramientas no están disponibles, necesita un pequeño 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
¿Qué es esta locura? Consulte esta respuesta para obtener una explicación de las técnicas que hacen que esto sea seguro para los nombres de archivos locos.
-mindepth
's?
find
; He editado la respuesta para incluir una solución que no sea GNU.
Hay muchas respuestas complicadas arriba, esto parece más simple y rápido que todas:
find . -maxdepth 1 | sort -f | uniq -di
Si desea encontrar nombres de archivos duplicados en subdirectorios, debe comparar solo el nombre del archivo, no la ruta completa:
find . -maxdepth 2 -printf "%f\n" | sort -f | uniq -di
Editar: Shawn J. Goff ha señalado que esto fallará si tiene nombres de archivo con caracteres de nueva línea. Si está utilizando las utilidades de GNU, también puede hacer que funcionen:
find . -maxdepth 1 -print0 | sort -fz | uniq -diz
La opción -print0
(para buscar) y -z
(para ordenar y uniq) hacen que funcionen en cadenas terminadas en NUL, en lugar de cadenas terminadas en nueva línea. Como los nombres de archivo no pueden contener NUL, esto funciona para todos los nombres de archivo.
Ordene la lista de nombres de archivo sin distinción entre mayúsculas y minúsculas e imprima duplicados. sort
tiene una opción para ordenar sin distinción entre mayúsculas y minúsculas. También lo hace GNU uniq
, pero no otras implementaciones, y todo lo que puede hacer uniq
es imprimir cada elemento en un conjunto de duplicados, excepto el primero que se encuentre. Con las herramientas GNU, suponiendo que ningún nombre de archivo contenga una nueva línea, hay una manera fácil de imprimir todos los elementos, excepto uno en cada conjunto de duplicados:
for x in *; do printf "%s\n" "$x"; done |
sort -f |
uniq -id
Portablemente, para imprimir todos los elementos en cada conjunto de duplicados, suponiendo que ningún nombre de archivo contenga una nueva línea:
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 }'
Si necesita acomodar nombres de archivo que contengan nuevas líneas, vaya a Perl o Python. Tenga en cuenta que es posible que necesite modificar la salida, o mejor hacer su procesamiento adicional en el mismo idioma, ya que el código de muestra a continuación usa nuevas líneas para separar los nombres en su propia salida.
perl -e '
foreach (glob("*")) {push @{$f{lc($_)}}, $_}
foreach (keys %f) {@names = @{$f{$_}}; if (@names > 1) {print "$_\n" foreach @names}}
'
Aquí hay una solución zsh pura. Es un poco detallado, ya que no hay una forma integrada de mantener los elementos duplicados en una matriz o resultado global.
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
Sin GNU find
:
LANG=en_US ls | tr '[A-Z]' '[a-z]' | uniq -c | awk '$1 >= 2 {print $2}'
tr
es muy probable que cause estragos en cualquier conjunto de caracteres que use más de un byte por carácter. Solo los primeros 256 caracteres de UTF-8 son seguros cuando se usan tr
. De Wikipedia tr (Unix) . La mayoría de las versiones tr
, incluyendo GNU tr
y Unix clásico tr
, operan en SINGLE BYTES y no son compatibles con Unicode ..
uniq
tiene una bandera que no distingue entre mayúsculas y minúsculas i.
Finalmente lo logré de esta manera:
find . | tr '[:upper:]' '[:lower:]' | sort | uniq -d
Utilicé en find
lugar de ls
porque necesitaba la ruta completa (muchos subdirectorios) incluida. No encontré cómo hacer esto ls
.
sort
y uniq
tienen banderas de ignorar mayúsculas y minúsculas, f e i respectivamente.
Para cualquier otra persona que quiera cambiar el nombre, etc., uno de los archivos:
find . -maxdepth 1 | sort -f | uniq -di | while read f; do echo mv "$f" "${f/.txt/_.txt}"; done