Bir kabuk komut dosyasındaki bir dizindeki dosyaların listesi nasıl alınır?


159

Kabuk betiği kullanarak bir dizinin içeriğini almaya çalışıyorum.

Benim senaryom:

for entry in `ls $search_dir`; do
    echo $entry
done

$search_dirgöreceli bir yol nerede . Ancak, $search_diradlarında boşluk bulunan birçok dosya içerir. Bu durumda, bu komut dosyası beklendiği gibi çalışmaz.

Kullanabileceğimi biliyorum for entry in *, ama bu sadece mevcut dizinim için işe yarayacaktır.

O dizine geçebileceğimi biliyorum, for entry in *sonra tekrar değiştirebiliyorum, ama özel durumum bunu yapmamı engelliyor.

İki göreceli yolum var $search_dirve $work_dirher ikisinde de aynı anda çalışmam gerekiyor, bunları içinde dosya oluşturma / silme vb.

Peki şimdi ne yapacağım?

PS: Ben bash kullanıyorum.

Yanıtlar:


274
for entry in "$search_dir"/*
do
  echo "$entry"
done

4
Neden for entry in "$search_dir/*"işe yaramadığını açıklayabilir misiniz ? Neden /*tekliflerin dışına koymamız gerekiyor?
mrgloom

6
@mrgloom: Çünkü kabuğun joker karakteri yerinden oynatmasına izin vermelisin.
Ignacio Vazquez-Abrams

daha findhızlı olmaz mıydı ?
Alexej Magura

4
Çözüm tam yolu verir. Geçerli dizinde ne olduğunu listelemek istersem ne olur?
ThatsRightJack

1
@mrgloom bunu yapmak istiyorsanız bunu başarabilirsinizfor entry in "${search_dir}/*"
funilrys

28

Buradaki diğer cevaplar harika ve sorunuzu cevaplıyor, ancak bu "bash dizinindeki dosyaların listesini al" için en iyi google sonucudur (bu da bir dosya listesini kaydetmek için bakıyordum), bu yüzden bir yazı yayınlayacağımı düşündüm bu sorunun cevabı:

ls $search_path > filename.txt

Yalnızca belirli bir tür istiyorsanız (örn. .Txt dosyaları):

ls $search_path | grep *.txt > filename.txt

$ Search_path komutunun isteğe bağlı olduğunu unutmayın; ls> dosyaadı.txt geçerli dizini yapar.


Yalnızca .txt dosyalarını almak için grep kullanmaya gerek yoktur: `ls $ search_path / *. Txt> dosyaadı.txt '. Ama daha da önemlisi, dosya adlarını ayrıştırmak için ls komutunun çıktısını kullanmamalısınız.
Victor Zamanian

1
@VictorZamanian, lsdosya adlarını ayrıştırmak için neden çıktı kullanmamamız gerektiğini açıklayabilir misiniz ? Bunu daha önce duymamıştım.
samurai_jane

1
@samurai_jane Bu konuyla ilgili birçok bağlantı var, ancak ilk arama sonucu: mywiki.wooledge.org/ParsingLs . Ben bile burada ls çıktı ayrıştırmak için nedenleri BS olduğunu iddia eden SO üzerinde bir soru gördüm ve bu konuda çok ayrıntılı. Ancak cevaplar / cevaplar hala kötü bir fikir olduğunu iddia etti. Bir göz atın: unix.stackexchange.com/questions/128985/…
Victor Zamanian

26

Bu, sözdizimini anlamamın daha kolay olduğu bir yerde yapmanın bir yoludur:

yourfilenames=`ls ./*.txt`
for eachfile in $yourfilenames
do
   echo $eachfile
done

./geçerli çalışma dizinidir ancak herhangi bir yolla değiştirilebilir bir
*.txtşey döndürür
. txt lsKomutu doğrudan terminale yazarak kolayca listelenecekleri kontrol edebilirsiniz .

Temel olarak, yourfilenamesliste komutunun döndürdüğü her şeyi ayrı bir öğe olarak içeren bir değişken oluşturursunuz ve sonra bu döngüye girersiniz. eachfileDöngü, içinden geçtiği değişkenin tek bir öğesini, bu durumda bir dosya adını içeren geçici bir değişken oluşturur . Bu mutlaka diğer cevaplardan daha iyi değildir, ancak sezgisel buluyorum çünkü zaten lskomut ve for döngüsü sözdizimine aşinayım .


Bu, hızlı, gayri resmi bir komut dosyası veya tek satırlık bir dosya için sorun olmaz, ancak bir dosya adı glob tabanlı çözümlerden farklı olarak satırsonu içeriyorsa bozulur.
Soren Bjornstad

@SorenBjornstad tavsiye için teşekkürler! Dosya adlarında yeni satırlara izin verildiğini bilmiyordum, ne tür dosyalar olabilir? Mesela, bu yaygın olarak görülen bir şey mi?
rrr

Dosya adlarındaki yeni satırlar bu nedenle kötüdür ve bildiğim kadarıyla bunları kullanmak için meşru bir neden yoktur. Hiç vahşi doğada bir tane görmedim. Bununla birlikte, kötüye kullanım kullanarak dosya adlarını yeni satırlarla kötü amaçlı olarak oluşturmak tamamen mümkündür. (Örneğin, bir dizin dosyalarını içeren hayal A, Bve C. Sen denilen dosyaları oluşturmak B\nCve Dsonra bunları silmeyi tercih. Yazılım size olmasaydı bu hakkın yerine bile önceden var olan dosyalar B ve C silme bitebileceğini idare etmediğini Bunu yapmak için izin.)
Soren Bjornstad

19
for entry in "$search_dir"/* "$work_dir"/*
do
  if [ -f "$entry" ];then
    echo "$entry"
  fi
done

11
find "${search_dir}" "${work_dir}" -mindepth 1 -maxdepth 1 -type f -print0 | xargs -0 -I {} echo "{}"

1
Bunun oldukça eski olduğunu biliyorum ama son xargs -0 -i echo "{}"emri alamıyorum, bana biraz açıklamak ister misin? Özellikle bu -i echo "{}"kısım ne işe yarar? Ayrıca manşu -ianda kullanımdan kaldırılan sayfadan okudum ve -Iinsted kullanmalıyız .
drkg4b

1
-i{}arg ile yer değiştirir .
Noel Yap

Teşekkürler! Bu da benim gibi yavaş fikirli için yararlı olduğunu düşünüyorum komut {}ile eşleşmeleri ile değiştirilir dize olduğunu düşünüyorum find.
drkg4b

3
neden kullanıyorsunuz xargs? varsayılan olarak, findbulduklarını yazdırır ... her şeyi silebilirsiniz -print0.
gniourf_gniourf

1
Bunu yapmak boşluklu dosya girişlerini iyi işlemez.
Noel Yap

4
$ pwd; ls -l
/home/victoria/test
total 12
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  a
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  b
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  c
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:32 'c d'
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  d
drwxr-xr-x 2 victoria victoria 4096 Apr 23 11:32  dir_a
drwxr-xr-x 2 victoria victoria 4096 Apr 23 11:32  dir_b
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:32 'e; f'

$ find . -type f
./c
./b
./a
./d
./c d
./e; f

$ find . -type f | sed 's/^\.\///g' | sort
a
b
c
c d
d
e; f

$ find . -type f | sed 's/^\.\///g' | sort > tmp

$ cat tmp
a
b
c
c d
d
e; f

Varyasyonlar

$ pwd
/home/victoria

$ find $(pwd) -maxdepth 1 -type f -not -path '*/\.*' | sort
/home/victoria/new
/home/victoria/new1
/home/victoria/new2
/home/victoria/new3
/home/victoria/new3.md
/home/victoria/new.md
/home/victoria/package.json
/home/victoria/Untitled Document 1
/home/victoria/Untitled Document 2

$ find . -maxdepth 1 -type f -not -path '*/\.*' | sed 's/^\.\///g' | sort
new
new1
new2
new3
new3.md
new.md
package.json
Untitled Document 1
Untitled Document 2

Notlar:

  • . : geçerli klasör
  • -maxdepth 1özyinelemeli olarak aramak için kaldır
  • -type f: dizinleri değil dosyaları bulma ( d)
  • -not -path '*/\.*' : geri dönme .hidden_files
  • sed 's/^\.\///g': ekli ./listeden çıkar

0

Bir dizindeki dosyaları listelemenin başka bir yolu da (diğer yanıtlardan bazıları kadar etkili olmayan farklı bir araç kullanarak).

cd "search_dir"
for [ z in `echo *` ]; do
    echo "$z"
done

echo *Geçerli dizinin tüm dosyalarını çıktılar. forDöngü Stdout'a her dosya adını ve baskılar üzerinde dolaşır.

Ayrıca, dizin içindeki dizinleri arıyorsanız, bunu fordöngü içine yerleştirin :

if [ test -d $z ]; then
    echo "$z is a directory"
fi

test -d dosyanın bir dizin olup olmadığını kontrol eder.


0

Kabul edilen cevap, a ile önek döndürmez. Bunu yapmak için

for entry in "$search_dir"/* "$search_dir"/.[!.]* "$search_dir"/..?*
do
  echo "$entry"
done

-1

Linux sürümünde (x86_64 GNU / Linux) ile çalışıyorum aşağıdaki işler:

for entry in "$search_dir"/*
do
  echo "$entry"
done

-1: Bu, değişkenleri alıntılamaması dışında kabul edilen cevapla aynıdır. Alıntı yapmamak $search_dir, dizin adında boşluk varsa kopması anlamına gelir. (Bu durumda alıntı yapmaktan kurtulabilirsiniz $entry, ancak alıntı yapmak daha iyi bir uygulama olacaktır.)
Soren Bjornstad

Hatalısınız. Benim çözümüm, kabul edilen cevaba benzer olsa bile aynı değil. Ve yanlış DEĞİL, işe yarıyor. Mac OS dahil olmak üzere farklı unix sistemlerinde denediklerim ve bunların her birinde çalıştı. Boşlukları olan dosya, adında önde gelen boşluklar olsa bile düzgün bir şekilde görüntülenir. search_dir =. $ search_dir / * içine giriş için; echo $ girişini yapın; done ./ aa aaa.txt ./add ./apm_tables.txt Çözümün ÇALIŞMADIĞINI veya yanlış sonuçlar ürettiğini kanıtlayabildiğinizde, çözümleri yalnızca oylayabilirsiniz.
Andrushenko Alexander

Yorumumu biraz daha okursanız, sorunun dosya adı yerine dizin adındaki boşluklarla ilgili olduğunu göreceksiniz . Bu, sorgulayıcının karşılaştığı sorundan farklıdır, ancak yine de kodun yanlışlıkla kırılabileceği anlamına gelir! İşte çalışmıyor ne bir örnek: . Döngü iki kez, bir kez baskı ve ikinci kez çalışır , bu muhtemelen beklenen sonuç değildir. mkdir "x y"; touch "x y/1.txt"; search_dir="x y"; for entry in $search_dir/*; do echo $entry; donexy/*
Soren Bjornstad

Ve yanlış sıralanmamış değişkenlerin tehlikeli bir şekilde yanlış olduğunu düşünüyorum, bu da bir aşağı oyun temelini oluşturuyor. Dosyaların bırakarak arama dizinin tüm alt silmek için bu kodu göz önünde bulundurun: search_dir="x y"; for entry in $search_dir/*; do if [ -d "$entry" ]; then rm -rf "$entry"; fi; done. xGeçerli dizinde de bir dizin varsa, değişkeninizi alıntılamadığınız için bu dizin silinir!
Soren Bjornstad

Her zaman bir görev için oluşturulan bir kodu alırsınız, görevi biraz değiştirirsiniz ve kod yanlış olur. Sorulan soru için önerilen çözüm çalışmalarım. Ama ... bir geliştirici olarak argümanlarınızla aynı fikirdeyim: bir kodu daha sağlam ve sağlam hale getirebiliriz, bunu yapmalıyız. Bu yüzden qoutes ekleyeceğim. Bu, cevabımı yukarıda verilen cevapla aynı hale getirecektir, ancak diskussion uğruna (biri için yararlı olabilir) yanıtı da bırakıyorum.
Andrushenko Alexander

-1

Sadece bu basit komutu girin:

ls -d */

Michael Sisko
Vipul

ls (list) -d (yalnızca dizinleri listeler) * / (herhangi bir desenin ters eğik çizgi listeyi yalnızca dizinlerle sınırlar).
Michael Sisko
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.