Herhangi biri ls
, dizin adları listesi için bir şey yapmak ve her birini döngüden geçirmek ve bir şeyler yapmak için bir şablon kabuk betiğine sahip mi?
ls -1d */
Dizin adlarının listesini almak için yapmayı planlıyorum .
Herhangi biri ls
, dizin adları listesi için bir şey yapmak ve her birini döngüden geçirmek ve bir şeyler yapmak için bir şablon kabuk betiğine sahip mi?
ls -1d */
Dizin adlarının listesini almak için yapmayı planlıyorum .
Yanıtlar:
@ Shawn-j-goff ve diğerlerinin önerdiği gibi, bir kürenin yapacağı yerde kullanılamaz.
Sadece bir for..do..done
döngü kullanın :
for f in *; do
echo "File -> $f"
done
Sen değiştirebilirsiniz *
ile *.txt
ya da (bu konuda dosya, dizin, ya da bir şey) bir listesini döndürür başka bir topak, bir liste üreten bir komut, örneğin $(cat filelist.txt)
, ya da aslında bir liste ile değiştirin.
do
Döngü içinde sadece dolar işareti önekine sahip döngü değişkenine bakın ( $f
yukarıdaki örnekte olduğu gibi). Yapabilirsin echo
ya da istediğin başka bir şey yapabilirsin.
Örneğin .xml
, geçerli dizindeki tüm dosyaları yeniden adlandırmak için .txt
:
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
Ya da daha iyisi, eğer Bash kullanıyorsanız, alt kabuk oluşturmak yerine Bash parametre genişletmelerini kullanabilirsiniz:
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
for
Döngülerin çok suiistimal edildiğini ve çıktısını ayrıştırmaya çalışan tipik bir tuzak olduğunu gösterir ls
. @ DanielA.White, sen belki o yardımcı olmadı (veya potansiyel yanıltıcı) eğer gibi söylediğinden beri, dizinler göre hareket ediyoruz, bu cevabı unaccepting düşünün. Shawn J. Goff'un cevabı, sorununuza daha sağlam ve çalışan bir çözüm sağlamalıdır.
ls
, çıktıyı bir for
döngüde okumamalısınız , $()
`` yerine kullanmalı ve More Quotes ™ kullanmalısınız . @CoverosGene'in iyi niyetli olduğundan eminim, ama bu çok korkunç.
ls
olduğunu ls -1 | while read line; do stuff; done
. En azından bu bir boşluk için kırılmayacak.
mv -v
İhtiyacınız olmayanecho "moved $x -> $t"
ls
Dosya adlarını almak için çıktısını kullanmak kötü bir fikirdir . Arıza ve hatta tehlikeli senaryolara yol açabilir. Bunun nedeni, bir dosya adının karakter /
ve karakter dışında herhangi bir karakter içermesi ve bu null
karakterlerden herhangi ls
birini sınırlayıcı olarak kullanmamasıdır, bu nedenle bir dosya adında boşluk veya yeni satır varsa , beklenmeyen sonuçlar elde edersiniz.
Dosyalar üzerinde yineleme yapmanın çok iyi iki yolu vardır. Burada basitçe echo
dosya adıyla bir şeyler yaptığımı göstermek için kullandım ; Yine de her şeyi kullanabilirsiniz.
İlki, kabuğun doğal globbing özelliklerini kullanmaktır.
for dir in */; do
echo "$dir"
done
Kabuk */
, for
döngünün okuduğu ayrı argümanlara genişler ; dosya for
adında boşluk, satırsonu veya başka herhangi bir garip karakter olsa bile, her bir tam adı bir atom birimi olarak görecek; Listeyi hiçbir şekilde ayrıştırmıyor.
Eğer alt dizinleri içine yinelemeli gitmek istiyorsanız sizin kabuk gibi bazı genişletilmiş globbing özelliklere (olmadıkça, o zaman bu yapmayacağım bash
s' globstar
Kabuk bu özelliklere sahip değilse. Veya sağlamak istiyorsanız sizin komut çalışacağını çeşitli sistemlerde, bir sonraki seçenek kullanmaktır find
.
find . -type d -exec echo '{}' \;
Burada, find
komut arayacak echo
ve dosya isminin bir argümanını iletecektir. Bu bulduğu her dosya için bir kez yapar. Önceki örnekte olduğu gibi, dosya listesinin ayrıştırılması yoktur; bunun yerine, bir dosya tamamen bağımsız değişken olarak gönderilir.
-exec
Argümanın sözdizimi biraz komik görünüyor. find
ilk argümanı sonra alır ve -exec
çalışacak program olarak ve sonraki her argümanda, o programa geçmek için argüman olarak kabul eder. Görmesi -exec
gereken iki özel argüman var . İlki {}
; bu argüman, önceki bölümlerin find
oluşturduğu bir dosya adı ile değiştirilir . İkincisi ;
, bunun find
programa iletilecek olan argümanlar listesinin sonu olduğunu bilmesini sağlayan ; find
Buna ihtiyacı var çünkü find
exec'd programı için amaçlanan ve amaçlanmayan daha fazla argümanla devam edebilirsiniz . Bunun nedeni \
, kabuğun da davranmasıdır.;
özel olarak - bir komutun sonunu temsil eder, bu yüzden ondan kaçmamız gerekir, böylece kabuk find
onu kendisi için tüketmekten ziyade bir argüman olarak verir ; özel olarak işlem görmemesi için kabuğun elde edilmesinin bir başka yolu tırnak içine almaktır: bu amaçla ';'
olduğu gibi çalışır \;
.
find
. Yapılabilecek büyü var ve hatta algılanan sınırlamaları bile -exec
çözülebiliyor. -print0
Seçeneği de kullanılmak için değerlidir xargs
.
İçinde boşluk olan dosyalar için aşağıdaki gibi bir değişkeni alıntıladığınızdan emin olmalısınız:
for i in $(ls); do echo "$i"; done;
veya giriş alanı ayırıcı (IFS) ortam değişkenini değiştirebilirsiniz:
IFS=$'\n';for file in $(ls); do echo $i; done
Son olarak, ne yaptığınıza bağlı olarak, ls'ye ihtiyacınız olmayabilir:
for i in *; do echo "$i"; done;
\n
yetersiz. Çıktısını ayrıştırmayı önermek hiçbir zaman iyi bir fikir değildir ls
.
Eğer GNU Parallel http://www.gnu.org/software/parallel/ kurulu ise bunu yapabilirsiniz:
ls | parallel echo {} is in this dir
.Txt dosyasının tümünü .xml olarak yeniden adlandırmak için:
ls *.txt | parallel mv {} {.}.xml
Daha fazla bilgi için GNU Parallel için tanıtım videosunu izleyin: http://www.youtube.com/watch?v=OpaiGYxkSuQ
Neden IFS'yi yeni bir satıra ayarlamıyor, sonra ls
bir dizideki çıktısını alıyorsunuz? IFS'yi yeni satıra ayarlamak, komik karakterlerle ilgili sorunları dosya adlarında çözmelidir; ls
Bir sıralama düzeni tesisi olduğundan, kullanmak güzel olabilir.
(Testte, IFS'yi ayarlamakta zorluk çekiyordum \n
ancak burada başka bir yerde önerildiği gibi newline backspace çalışmalarına ayarlamakta zorlandım ):
Örneğin (istenilen ls
arama kalıbının geçtiğini varsayarsak $1
):
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
FILES=($(/bin/ls "$1"))
for AFILE in ${FILES[@]}
do
... do something with a file ...
done
IFS=$SAVEIFS
Bu özellikle OS X'te kullanışlıdır, örneğin, oluşturma tarihine göre (en eskiden en yeniye) sıralanan dosyaların listesini yakalamak için ls
komuttur ls -t -U -r
.
\n
yetersiz. Yalnızca geçerli çözümler, yol adı genişletmeli bir for döngüsü kullanır veya find
.
Bunu böyle yapıyorum, ancak muhtemelen daha etkili yollar var.
ls > filelist.txt
while read filename; do echo filename: "$filename"; done < filelist.txt
ls | while read i; do echo filename: $i; done