yinelenen dosya adlarında büyük / küçük harfe duyarlı olmayan arama


17

Ben kasa (büyük ve / veya küçük harf) ne olursa olsun, yinelenen dosya adlarına sahip bir dizindeki tüm dosyaları bulmak için bir yolu var mı?

Yanıtlar:


14

Kullanılabilir GNU yardımcı programlarınız varsa (veya en azından sıfır sonlu satırlarla başa çıkabilecek bir küme), başka bir yanıtın harika bir yöntemi vardır:

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

Not: çıkışın sıfır sonlu dizeleri olacaktır; ileride işlemek için kullandığınız araç bunu kaldırabilmelidir.

Sıfır sonlu satırlarla ilgilenen araçların yokluğunda veya kodunuzun bu tür araçların bulunmadığı ortamlarda çalıştığından emin olmak istiyorsanız, küçük bir komut dosyasına ihtiyacınız vardır:

#!/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

Bu delilik nedir? Bunu çılgın dosya adları için güvenli hale getiren tekniklerin açıklaması için bu cevaba bakınız .


1
Ben sadece benzer bir sonrası gönderecektim ... Ama daha kötü cevap :)
rozcietrzewiacz

2
-mindepth'Lere gerçekten ihtiyacınız var mı?
rozcietrzewiacz

Solaris kullanıyorum. / Usr / bin / bahsettiğinizi buluyor mu? Kullanmayı denedim ve bana birçok hata verdim.
20'de lamcro

@lamcro Hayır, Solaris GNU'ları kullanmaz find; Cevabı GNU olmayan bir çözüm içerecek şekilde düzenledim.
Shawn J. Goff

Tamam. Sadece bir metin dosyasına yapıştırıp yürütme hakları veriyor muyum?
22'de lamcro

12

Yukarıda birçok karmaşık cevap var, bu hepsinden daha basit ve daha hızlı görünüyor:

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

Alt dizinlerde yinelenen dosya adları bulmak istiyorsanız, tüm yolu değil, yalnızca dosya adını karşılaştırmanız gerekir:

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

Edit: Shawn J. Goff yeni satır karakterleri ile dosya adlarınız varsa, bu başarısız olacağını belirtti. GNU yardımcı programlarını kullanıyorsanız, bunları da çalıştırabilirsiniz:

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

-print0(Bulma işlemi için) ve -zyeni satır dizeleri sonlandırıldı yerine, seçenek bunlar neden boş karakter sonlandırmalı dizgeler üzerinde çalışmaya (tür ve uniq). Dosya adları NUL içeremediğinden, bu tüm dosya adları için geçerlidir.


1
Ama Shawn J. Goff'un cevabı hakkındaki yorumuma bakın, bulmak için -print0 seçeneğini ve uniq ve sort'e -z seçeneğini ekleyebilirsiniz. Ayrıca, -f üzerinde de istiyorsun. Sonra işe yarıyor. (Bunu cevabınızda düzenleyeceğim, onaylamazsanız geri
dönmekten çekinmeyin

Son komut satır başı olmadan bana çıktı veriyor (sonuç tek satırda). Komutu çalıştırmak için Red Hat Linux kullanıyorum. İlk komut satırı benim için en uygun olanı.
Paz

2

Dosya adları listesini büyük / küçük harfe duyarlı olmayan bir şekilde sıralayın ve kopyaları yazdırın. sortbüyük / küçük harfe duyarlı olmayan sıralama seçeneği vardır. GNU da öyle uniq, ancak diğer uygulamalar değil ve yapabileceğiniz tek şey, uniqkarşılaşılan ilk şey hariç her öğeyi bir kopya halinde yazdırmak. GNU araçlarıyla, hiçbir dosya adının yeni satır içermediğini varsayarsak, her yinelenen kümede bir tane olmak üzere tüm öğeleri yazdırmanın kolay bir yolu vardır:

for x in *; do printf "%s\n" "$x"; done |
sort -f |
uniq -id

Taşınabilir olarak, hiçbir dosya adının yeni satır içermediğini varsayarak, her yinelenen kümedeki tüm öğeleri yazdırmak için:

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 }'

Yeni satırlar içeren dosya adlarını barındırmanız gerekiyorsa Perl veya Python'a gidin. Aşağıdaki örnek kod, kendi çıktısında adları ayırmak için yeni satırlar kullandığından, çıktıyı düzeltmeniz veya aynı dilde daha fazla işlem gerçekleştirmeniz gerekebilir.

perl -e '
    foreach (glob("*")) {push @{$f{lc($_)}}, $_}
    foreach (keys %f) {@names = @{$f{$_}}; if (@names > 1) {print "$_\n" foreach @names}}
'

İşte saf bir zsh çözümü. Yinelenen öğeleri bir dizi veya glob sonucunda tutmanın yerleşik bir yolu olmadığından, biraz ayrıntılıdır.

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 olmadan find:

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


2
trolduğu çok karakterin başına tek bayt daha kullanan herhangi bir karakter setinde wreak tahribat ihtimali. UTF-8'in sadece ilk 256 karakteri kullanıldığında güvenlidir tr. Gönderen Vikipedi tr (Unix) .. Çoğu sürümleri trGNU dahil, trve klasik Unix tr, TEK BAYT'lardan ameliyat ve Unicode uyumlu olmayan ..
Peter.O

1
Önceki yorumumu güncelleyin .. UTF-8'in sadece ilk 128 karakteri güvende. Sıra aralığı 0..127'nin üzerindeki tüm UTF-8 karakterlerinin tümü çok baytlıdır ve diğer karakterlerde ayrı bayt değerlerine sahip olabilir. Yalnızca 0..127 aralığındaki baytların benzersiz bir karakterle bire bir ilişkisi vardır.
Peter.O

Artı uniq, büyük / küçük harf duyarsız bir bayrağa sahiptir i.
Jamie Kitson

1

Sonunda şu şekilde başardım:

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

Ben tam yol (alt dizinler bir sürü) dahil neden findyerine kullandım ls. Bunu nasıl yapacağımı bulamadım ls.


2
Hem sortve uniqsırasıyla görmezden durum bayrakları, f ve i var.
Jamie Kitson

-1

Dosyalardan birini vb. Yeniden adlandırmak isteyen herkes için:

find . -maxdepth 1 | sort -f | uniq -di | while read f; do echo mv "$f" "${f/.txt/_.txt}"; done
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.