пошук нечутливих до регістру дублікатів імен файлів


17

У мене є спосіб знайти всі файли в каталозі з повторюваними іменами файлів, незалежно від корпусу (верхнього та / або нижнього регістру)?

Відповіді:


14

Якщо у вас є утиліти 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

Що це за божевілля? Дивіться цю відповідь для пояснення методів, які роблять це безпечним для шалених імен файлів.


1
Я якраз збирався опублікувати подібне ... Але гірша відповідь :)
rozcietrzewiacz

2
Вам справді потрібні -mindepth's?
rozcietrzewiacz

Я використовую Solaris. Знаходиться / usr / bin / той, про який ти говориш? Я спробував його використати і дав мені багато помилок.
ламкро

@lamcro Ні, Solaris не використовує GNU find; Я відредагував відповідь, щоб включити рішення, яке не стосується GNU.
Шон Дж. Гофф

Добре. Я просто вставлю його в текстовий файл і надаю йому права на виконання?
ламкро

12

Вище є багато складних відповідей, це здається простішим та швидшим за всі:

find . -maxdepth 1 | sort -f | uniq -di

Якщо ви хочете знайти дублікати імен файлів у підкаталогах, вам потрібно порівняти лише ім'я файлу, а не весь шлях:

find . -maxdepth 2 -printf "%f\n" | sort -f | uniq -di

Редагувати: Шон Дж. Гофф зазначив, що це не вдасться, якщо у вас є назви файлів з символами нового рядка. Якщо ви використовуєте утиліти GNU, ви також можете зробити ці роботи:

find . -maxdepth 1 -print0 | sort -fz | uniq -diz

Параметр -print0(для пошуку) та -zпараметр (для сортування та uniq) змушує їх працювати над рядками, що закінчуються NUL, замість рядків, що закінчуються новою лінією. Оскільки імена файлів не можуть містити NUL, це працює для всіх імен файлів.


1
Але дивіться мій коментар до відповіді Шона Дж. Гоффа, ви можете додати параметр -print0 для пошуку, а -z варіант - uniq та сортування. Крім того, ви хочете -f на сортування також. Тоді це працює. (Я відредагую це у вашій відповіді,
сміливо повертайтеся,

Остання команда дає мені вихід без повернення каретки (результат - це все в одному рядку). Я використовую Red Hat Linux для запуску команди. Перший командний рядок працює для мене найкраще.
Нд

2

Сортуйте список імен файлів невідчутним до регістру та друкуйте дублікати. 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

1

Без GNU find:

LANG=en_US ls | tr '[A-Z]' '[a-z]' | uniq -c | awk '$1 >= 2 {print $2}'


2
trце дуже ймовірно , щоб посіяти хаос на будь-який набір символів , який використовує більш одного байта на символ. Лише перші 256 символів UTF-8 безпечні під час використання tr. З Вікіпедії tr (Unix) . Більшість версій tr, включаючи GNU trі класичний Unix tr, працюють на
ЄДИНІ БЮТИ

1
Оновлення до мого попереднього коментаря .. тільки перші 128 символів UTF-8 є безпечними. Усі символи UTF-8 вище порядкового діапазону 0..127 є багатобайтовими і можуть мати окремі значення байтів в інших символах. Тільки байти в діапазоні 0..127 мають індивідуальну асоціацію до унікального символу.
Пітер.O

Плюс uniqмає прапор, нечутливий до регістру i.
Джеймі Кітсон

1

Нарешті мені вдалося так:

find . | tr '[:upper:]' '[:lower:]' | sort | uniq -d

Я використовував findзамість lsпричини мені потрібен повний шлях (безліч підкаталогів). Я не знайшов, як це зробити ls.


2
Обидва sortі uniqмають ігнорувати регістр прапори, F і I відповідно.
Джеймі Кітсон

-1

Для всіх, хто хоче перейменувати тощо, один із файлів:

find . -maxdepth 1 | sort -f | uniq -di | while read f; do echo mv "$f" "${f/.txt/_.txt}"; done
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.