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 f
adlarında bir yerde bulunan tüm dosyaları bulur ( -name '*f*'
). Daha sed
sonra, 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
).
sed
Komutu 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 sort
komutların çoğu gereksiz -u
yapan 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, find
komutunuz destekliyorsa, find
doğ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/'
-E
MacOS'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 -printf
operatö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.sed
awk
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
, grep
ve 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, dirname
bunun 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 -5
sadece 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!
time
2 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 -5
sadece 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 echo
kullanmak istediğiniz komutu değiştirin .
İle zsh
:
typeset -aU dirs # array with unique values
dirs=(**/*f*(D:h))
printf '%s\n' $dirs
uniq
Karışı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