Bir dosyada tutulan yolların bir listesini ayrıştırmak için taban adını kullanma


9

Mac OSX çalıştırıyorum ve aynı ada sahip dosya sayısını bulmak için komut satırını kullanmaya çalışıyorum.

Aşağıdaki komutu kullanmaya çalıştım:

find ~ -type f -name "*" -print | basename | sort | uniq -d > duplicate_files

Çalışmıyor! Aşağıdakileri yaptığımda:

find ~ -type f -name "*" -print > duplicate_files

Sonra duplicate_files tüm dosyalarımın yollarını içerir. Bu yüzden sorunun olduğunu düşünüyorum basename- standart girişi kabul etmiyor. Sonra aşağıdakileri denedim:

basename $(find ~ -type f -name "*" -print) > duplicate_files

ama yine de işe yaramadı. İnternette arama yapmak pek sevinç vermiyor gibi görünüyor. Herhangi bir düşünce en hoş geldiniz.

Yanıtlar:


16

basename komut satırı bağımsız değişkeninde çalışır, standart girdiden okunmaz.

basenameYardımcı programı çağırmanıza gerek yoktur ve daha iyi olmazsınız: tek yapacağı şey parçayı sondan önce çıkarmaktır ve /her giriş için harici bir komut çağırmak yavaş olur, bir metin işleme kullanabilirsiniz yerine.

find ~ -type f | sed 's!.*/!!' | sort | uniq -d

Dosyaların konumunu izlemek daha yararlı olabilir. Ada göre sıralama, yinelenenleri bulmayı kolaylaştırır, ancak sortson alanı kullanma seçeneği yoktur. Yapabileceğiniz şey, son ayrılan /alanı başlangıca kopyalamak, sıralamak ve daha sonra, kopyaları ayıklamak ve sunmak için biraz ad hoc awk işleme kullanmaktır.

find ~ -type f |
sed 's!.*/\(.*\)!\1/&!' |   # copy the last field to the beginning
sort -t/ -k1,1 |
cut -d/ -f2- |   # remove the extra first field (could be combined with awk below)
awk -F / '{
    if ($NF == name) {
        if (previous != "") {print previous; previous = ""}
        print
    } else {
        previous = $0
        name = $NF
    }
'

(Dosya adlarınızdan hiçbirinin yeni satır karakteri içermediğini varsayıyorum.)


Süper teşekkürler. Bu tam olarak yapmaya çalıştığım şeydi ... çok yararlı
JohnB

7

Neden findsadece dosya adını çıktılamak için yerleşik özellikleri kullanmıyorsunuz :

find ~ -type f -printf '%f\n' | sort | uniq -c

(GNU olduğunu varsayar find) veya en azından şu şekilde:

find ~ -exec basename {} \; | sort | uniq -c

basename dikey olarak okuyamaz veya aynı anda birden fazla dosyayı işleyemez.

ps. -name '*'Tüm dosyaları listelemek isteyip istemediğinizi belirtmeniz gerekmez . Bu varsayılan bir seçenektir.


Teşekkürler - '-printf' OS X UNIX için çalışmaz
JohnB

Ve ikinci sürümü denediğimde basename: unknown primary or operator. Bahşiş için teşekkürler-name "*"
JohnB

Bu garip. -printfPosix man sayfasında bile görebiliyorum . İkinci yoldaki hata hakkında, cevabımda yazım hatası nedeni. Sabit. Lütfen bir kez daha deneyebilir misiniz?
acele

Ayrıca -printfben ile olsun -printf: unknown primary or operator. Ayrıca Nutshell referans kitabındaki Unix'i kontrol ettiğimde bir GNU / Linux seçeneği olarak listelendi - OSX hakkında bir şey söylemiyor
JohnB

1
Aslında en iyi kaynak man findkonsolunuzda olurdu :)
acele

4

Bu benim için OSX'te işe yarıyor gibi görünüyor:

find ~ -type f -exec basename -a {} + | sort | uniq -d

Evet - bu çok teşekkürler - +ilgisizlik komutta ne anlama geliyor ?
JohnB

2
Bu yararlı mı? Lütfen oy verin.
suspectus

Bu - 15 üne ihtiyacım var beacuase oy
veremiyorum

@StephaneChazelas: BSD taban adı için man sayfasına göre , yürütülebilir dosya birden fazla dizeyi argüman olarak alabilir. OSX'i iki kez kontrol ettim, işe yarıyor.
rahmu

1
Tamam üzgünüm, düzeltilmiş duruyorum. BSD uzantısının farkında değildim. Ancak, tam olarak iki dosya varsa bu hala başarısız olur. Bu vakayı da kapsayacak -aseçeneği eklemeniz gerekir .
Stéphane Chazelas

2

Alternatifler (dosya adlarında yeni satır olmadığını varsayar):

find ~ -type f | awk -F/ '{print $NF}' | sort | uniq -d

2

Aşağıdaki gibi istediğiniz çıktıyı almak için xargsile kullanabilirsiniz basename:

find ~ -type f -name "*" -print | xargs -l basename | sort | uniq -d > duplicate_files

0

bashİlişkilendirilebilir dizileri işleyen son sürümüyle , aşağıdakiler ek olarak katıştırılmış yeni satırlara sahip yol adlarını da işleyecektir:

#!/bin/bash

topdir=$HOME

shopt -s globstar  # enable the ** glob

declare -A count

# count the number of times each filename (base name) occurs
for pathname in "$topdir"/**; do
    # skip names that are not regular files (or not symbolic links to such files)
    [ ! -f "$pathname" ] && continue

    # get the base name
    filename=${pathname##*/}

    # add one to this base name's count
    count[$filename]=$(( ${count[$filename]} + 1 ))
done

# go through the collected names and print any name that
# has a count greater than one
for filename in "${!count[@]}"; do
    if [ "${count[$filename]}" -gt 1 ]; then
        printf 'Duplicate filename: %s\n' "$filename"
    fi
done

Harici bir yardımcı program kullanılmaz.

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.