Yanıtlar:
find . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort |uniq
Yukarıdakiler, geçerli dizinin altındaki ( .) normal dosyalar ( -type f) olan ve fadlarında bir yerde bulunan tüm dosyaları bulur ( -name '*f*'). Daha sedsonra, sadece dizin adını bırakarak dosya adını kaldırır. Sonra, dizinlerin listesi sıralanır ( sort) ve kopyalar kaldırılır ( uniq).
sedKomutu tek yerine oluşur. Düzenli ifadeyle eşleşmeleri arar /[^/]+$ve eşleşen hiçbir şeyi hiçbir şeyle değiştirmez. Dolar işareti çizginin sonu anlamına gelir. [^/]+'eğik çizgi olmayan bir veya daha fazla karakter anlamına gelir. Böylece, /[^/]+$son eğik çizgiden çizginin sonuna kadar olan tüm karakterler anlamına gelir. Başka bir deyişle, bu tam yolun sonundaki dosya adıyla eşleşir. Bu nedenle, sed komutu dosya adını kaldırır ve dosyanın içinde bulunduğu dizinin adını değiştirmeden bırakır.
Modern sortkomutların çoğu gereksiz -uyapan bir bayrağı destekler uniq. GNU sed için:
find . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort -u
Ve MacOS sed için:
find . -type f -name '*f*' | sed -E 's|/[^/]+$||' |sort -u
Ayrıca, findkomutunuz destekliyorsa, finddoğrudan dizin adlarını yazdırmanız da mümkündür . Bu, şu gereksinimden kaçınır sed:
find . -type f -name '*f*' -printf '%h\n' | sort -u
Yukarıdaki sürümlerde yeni satırlar içeren dosya adları ile karıştırılacak. NUL sonlandırılmış dizgilerde sıralama yapmak daha sağlam bir çözümdür:
find . -type f -name '*f*' -printf '%h\0' | sort -zu | sed -z 's/$/\n/'
-EMacOS'ta gösterilmek üzere cevap güncellendi .
Neden bunu denemiyorsun:
find / -name '*f*' -printf "%h\n" | sort -u
find aslında oldukça seyrek-olan -printfoperatör olduğunu değil belirtilmedi. Bu BSD ile çalışmıyor find. Yani, "tamamen POSIX uyumlu" değil . (Her sort -u ne kadar POSIX'te .)
Bunu yapmak için kullanabileceğiniz 2 yöntem var. Biri dize ayrıştırırken diğeri her dosya üzerinde çalışacaktır. İpin ayrıştırılması gibi bir araç kullanın , ya da açıkça daha hızlı olacağına dair bir araç kullanın grep, fakat işte size her ikisini de gösteren ve 2 yöntemi nasıl "profilleyebileceğinizi" gösteren bir örnek.sedawk
Aşağıdaki örnekler için aşağıdaki verileri kullanacağız
$ touch dir{1..3}/dir{100..112}/file{1..5}
$ touch dir{1..3}/dir{100..112}/nile{1..5}
$ touch dir{1..3}/dir{100..112}/knife{1..5}
*f*Dosyalardan bazılarını sil dir1/*:
$ rm dir1/dir10{0..2}/*f*
Burada, aşağıdaki araçları kullanacağız find, grepve sort.
$ find . -type f -name '*f*' | grep -o "\(.*\)/" | sort -u | head -5
./dir1/dir103/
./dir1/dir104/
./dir1/dir105/
./dir1/dir106/
./dir1/dir107/
Daha önce olduğu gibi aynı takım zinciri, dirnamebunun yerine kullanacağımız bu süre dışında grep.
$ find . -type f -name '*f*' -exec dirname {} \; | sort -u | head -5
./dir1/dir103
./dir1/dir104
./dir1/dir105
./dir1/dir106
./dir1/dir107
NOT: Yukarıdaki örnekler head -5sadece bu örnekler için uğraştığımız çıktı miktarını sınırlamak için kullanılmaktadır . Tam listeni almak için normalde kaldırılırlar!
time2 yaklaşıma bakmak için kullanabiliriz .
dizinadı
real 0m0.372s
user 0m0.028s
sys 0m0.106s
grep
real 0m0.012s
user 0m0.009s
sys 0m0.007s
Yani mümkünse dizelerle başa çıkmak her zaman en iyisidir.
grep ve PCRE
$ find . -type f -name '*f*' | grep -oP '^.*(?=/)' | sort -u
sed
$ find . -type f -name '*f*' | sed 's#/[^/]*$##' | sort -u
awk
$ find . -type f -name '*f*' | awk -F'/[^/]*$' '{print $1}' | sort -u
İşte yararlı buluyorum:
find . -type f -name "*somefile*" | xargs dirname | sort | uniq
Bu cevap utanmadan slm cevabına dayanmaktadır. İlginç bir yaklaşımdı, ancak dosya ve / veya dizin isimlerinin özel karakterleri (boşluk, yarı sütun ...) olsaydı bir kısıtlaması vardı. İyi bir alışkanlık kullanmaktır find /somewhere -print0 | xargs -0 someprogam.
Aşağıdaki örnekler için aşağıdaki verileri kullanacağız
mkdir -p dir{1..3}/dir\ {100..112}
touch dir{1..3}/dir\ {100..112}/nile{1..5}
touch dir{1..3}/dir\ {100..112}/file{1..5}
touch dir{1..3}/dir\ {100..112}/kni\ fe{1..5}
*f*Dosyalardan bazılarını sil dir1/*/:
rm dir1/dir\ 10{0..2}/*f*
$ find -type f -name '*f*' -print0 | sed -e 's#/[^/]*\x00#\x00#g' | sort -zu | xargs -0 -n1 echo | head -n5
./dir1/dir 103
./dir1/dir 104
./dir1/dir 105
./dir1/dir 106
./dir1/dir 107
NOT : Yukarıdaki örnekler head -5sadece bu örnekler için uğraştığımız çıktı miktarını sınırlamak için kullanılmaktadır . Tam listeni almak için normalde kaldırılırlar! ayrıca echokullanmak istediğiniz komutu değiştirin .
İle zsh:
typeset -aU dirs # array with unique values
dirs=(**/*f*(D:h))
printf '%s\n' $dirs
uniqKarışımı atmak , zaten yan yana olan tekrarlanan çizgileri kaldırarak çok yardımcı olur.find . -type f -name '*f*' -printf '%h\0' | uniq -z | sort -zu | tr '\0' '\n'. Veya aletleriniz biraz daha eskiyse, uniq -z seçeneğine sahip olmayabilir.find . -type f -name '*f*' -printf '%h\n' | uniq | sort -u