Linux'ta dizinler arasında nasıl geçiş yapılır?


168

Linux'ta bash'de bir komut dosyası yazıyorum ve belirli bir dizindeki tüm alt dizin adlarından geçmem gerekiyor. Bu dizinler arasında nasıl geçiş yapabilirim (ve normal dosyaları atlayabilirim)?

Örneğin:
verilen dizin /tmp/
aşağıdaki alt dizinlere sahip olmasıdır:/tmp/A, /tmp/B, /tmp/C

A, B, C almak istiyorum.


Yanıtlar:


129
cd /tmp
find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n'

Kısa bir açıklama:

  • find dosyaları bulur (oldukça açık)

  • .sonra geçerli dizin vardır cdolduğunu /tmp(IMHO bu sahip daha esnektir /tmpdoğrudan findkomuta. Yalnızca bir yere sahip, cddeğişim için, daha fazla eylemler bu klasörde yer almak istiyorsanız)

  • -maxdepth 1ve yalnızca geçerli dizine baktığından ve sonuca kendini eklemediğinden -mindepth 1emin olunfind.

  • -type d sadece dizinleri arar

  • -printf '%f\n her isabet için yalnızca bulunan klasörün adını (artı yeni satır) yazdırır.

Et voilà!


Bu arada: Tüm yanıtların gizli klasörler de bulacağını unutmayın (yani, nokta ile başlayan klasörler)! Bunu istemiyorsanız, printf veya exec seçeneklerinden önce -regex '\ ./ [^ \.]. *' 'Ekleyin.
Boldewyn

1
Yararlı - her isabet için sadece bir komut yürütmeniz gerekiyorsa ;-) - Sadece yürütmek için birkaç komutum var :-(.
Martin

Sorun değil: Bu çözümü uyarlayın: transnum.blogspot.de/2008/11/… Döngünün içinde delirebilirsinizwhile..done .
1414

1
Bu, bazı kullanım durumları için çok güzel bir yöntemdir; find' -execseçeneği her dosya / dizin için herhangi bir komutu çalıştırmanızı sağlar.
jtpereyda

451

Şimdiye kadar tüm cevaplar kullanın find, işte sadece kabuklu olanı. Durumunuzda harici araçlara gerek yok:

for dir in /tmp/*/     # list directories in the form "/tmp/dirname/"
do
    dir=${dir%*/}      # remove the trailing "/"
    echo ${dir##*/}    # print everything after the final "/"
done

18
+1 - findBir joker karaktere eğik çizgi ekleyebildiğiniz zaman neden rahatsız edersiniz
Tobias Kienzler

19
böylece for dir in */; do echo $dir; donegeçerli dizinde dizinleri içindir.
Ehtesh Choudhury

41
Ne dir=${dir%*/}ve ne echo ${dir##*/}yapıyor bir açıklama içerebilir güzel olurdu .
Jeremy S.

11
Bunun nedeni dir değişkeninin sonunda ters eğik çizgi içermesidir. Temiz bir isme sahip olmak için onu kaldırıyor. % sonunda / işaretini kaldıracaktır. ## başlangıçta / işaretini kaldıracaktır. Bunlar alt dizeleri işlemek için kullanılan işleçlerdir.
sfratini

8
Eşleşme yoksa, döngü tetiklenir /tmp/*/, dizinin gerçekten var olup olmadığını görmek için bir kontrol eklemek akıllıca olur.
Jrs42

41

Gizli dizinler (nokta ile başlayan) dahil olmak üzere tüm dizinler arasında aşağıdakilerle geçiş yapabilirsiniz:

for file in */ .*/ ; do echo "$file is a directory"; done

not: listeyi kullanmak */ .*/yalnızca klasörde en az bir gizli dizin varsa zsh içinde çalışır. Bash'da da gösterecek .ve..


Bash'ın gizli dizinleri içermesi için başka bir olasılık kullanmak olacaktır:

shopt -s dotglob;
for file in */ ; do echo "$file is a directory"; done

Sembolik bağlantıları hariç tutmak istiyorsanız:

for file in */ ; do 
  if [[ -d "$file" && ! -L "$file" ]]; then
    echo "$file is a directory"; 
  fi; 
done

Her çözümde yalnızca izleyen dizin adını (sorgulandığı gibi A, B, C) çıkarmak için bunu döngüler içinde kullanın:

file="${file%/}"     # strip trailing slash
file="${file##*/}"   # strip path and leading slash
echo "$file is the directoryname without slashes"

Örnek (boşluk içeren dizinlerle de çalışır):

mkdir /tmp/A /tmp/B /tmp/C "/tmp/ dir with spaces"
for file in /tmp/*/ ; do file="${file%/}"; echo "${file##*/}"; done

16

Boşluk içeren dizinlerle çalışır

Esinlenen Sorpigal

while IFS= read -d $'\0' -r file ; do 
    echo $file; ls $file ; 
done < <(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d -print0)

Orijinal yayın (Boşluklarla çalışmaz)

Boldewyn'den esinlenerek: Komutlu döngü örneği find.

for D in $(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d) ; do
    echo $D ;
done


6

En sık kullandığım teknik find | xargs. Örneğin, bu dizindeki her dosyayı ve tüm alt dizinlerini dünya tarafından okunabilir yapmak istiyorsanız, şunları yapabilirsiniz:

find . -type f -print0 | xargs -0 chmod go+r
find . -type d -print0 | xargs -0 chmod go+rx

-print0Seçenek yerine alanı NULL karakteri ile sona erer. -0Seçenek onun girişini aynı şekilde böler. Bu, boşluklu dosyalarda kullanılacak kombinasyon.

Bu komut zincirini her satır çıkışını alıp findbir chmodkomutun sonuna yapıştırarak resmedebilirsiniz .

Sonunda değil, ortada argümanı olarak çalıştırmak istediğiniz komut biraz yaratıcı olmanız gerekir. Örneğin, her alt dizine geçip komutu çalıştırmam gerekiyordu latemk -c. Bu yüzden kullandım ( Wikipedia'dan ):

find . -type d -depth 1 -print0 | \
    xargs -0 sh -c 'for dir; do pushd "$dir" && latexmk -c && popd; done' fnord

Bunun etkisi vardır for dir $(subdirs); do stuff; done, ancak adlarında boşluk bulunan dizinler için güvenlidir. Ayrıca, ayrı stuffkabuklar aynı kabukta yapılır, bu yüzden komutumda geçerli dizine geri dönmek zorundayız popd.


3

oluşturabileceğiniz minimal bash döngüsü (ghostdog74 cevabına dayanarak)

for dir in directory/*                                                     
do                                                                                 
  echo ${dir}                                                                  
done

bir sürü dosyayı dizine göre sıkıştırmak için

for dir in directory/*
do
  zip -r ${dir##*/} ${dir}
done                                               

Bu directory, yalnızca alt dizinleri değil, tüm dosyalarını listeler .
dexteritas

2

find . -type d -maxdepth 1


2
Ben sadece dizinlerin isimlerini istiyorum iken bu cevap, ben tam yolları almak dışında iyidir.
Erik Sapir

2

For döngüsünde birden çok komut yürütmek istiyorsanız, (bash> = 4) findile sonucunu mapfiledeğişken olarak kaydedebilir ve ile dizi arasında gezinebilirsiniz ${dirlist[@]}. Ayrıca boşluk içeren dizinlerle de çalışır.

findKomut dayanmaktadır cevap Boldewyn tarafından. findKomut hakkında daha fazla bilgiyi burada bulabilirsiniz.

IFS=""
mapfile -t dirlist < <( find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n' )
for dir in ${dirlist[@]}; do
    echo ">${dir}<"
    # more commands can go here ...
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.