Bir bash kabuk komut dosyasında, dize değerleri üzerinde yinelenen bir for döngüsü yazma


24

Kısaca, forbazı döngü kontrol değişkeninin ibelirtilen tamsayılar üzerinde yinelendiği bir döngü yazmanın mümkün olduğunu biliyorum . Örneğin, 1 ile 10 arasındaki tam sayıları basan bir bash shell betiği yazabilirim:

#!/bin/bash

for i in {1..10}
do
 echo $i
done

Dizelerin listesini sağlarsam, bunun yerine, dize olan bir döngü kontrol değişkeni üzerinde yineleme yapmak mümkün müdür? Örneğin, fnamebir dosya adını gösteren bir dize bulunduğunu varsayalım . Her dosya adı için bir dizi komut çağırmak istiyorum. Örneğin, fnameböyle bir komutu kullanarak içeriğini yazdırmak isteyebilirim :

#!/bin/bash

for fname in {"a.txt", "b.txt", "c.txt"}
do
 echo $fname
done

Başka bir deyişle, ilk yinelemede fnamedeğer fname="a.txt", ikinci yinelemede fnamedeğer fname="b.txt", vb. Olmalıdır. Ne yazık ki, yukarıdaki sözdiziminin oldukça doğru olmadığı görülüyor. Çıktıyı elde etmek istiyorum:

a.txt

b.txt

c.txt

ama yukarıdaki kodu denediğimde bu çıktıyı alıyorum:

{A.txt,

b.txt,

c.txt}

Lütfen değişkenin değerini / içeriğini yinelemeli olarak değiştirebilmem için doğru sözdizimini belirlememe yardım eder misiniz fname? Zaman ayırdığınız için teşekkür ederim.


5
Kaldır, {}(boşlukla ayrılmış) bir listede
Mat

3
Vasıtasıyla @Mat kaldırmak {} ve, s. Alternatif, boşlukları kaldırmaktır. Ya da "a.txt" "b.txt" "c.txt"ya {"a.txt","b.txt","c.txt"}. Ama {a..c}.txtbunun yerine tercih ederim .
Manatwork

Yanıtlar:


39

Doğru sözdizimi aşağıdaki gibidir:

#!/bin/bash

for fname in a.txt b.txt c.txt
do
  echo $fname
done

9
Ayrıca, bir dizi diziyi varsayarak fnames=( a.txt b.txt c.txt )sözdizimini de kullanabilirsiniz for f in ${fnames[@]}; do echo $f; done.

1
Bunun doğru mu for fname in a.txt b.txt c.txtve for fname in "a.txt" "b.txt" "c.txt"aynı sonuçları mı veriyorsun ?
Andrew,

Andrew, evet doğru. Aynı sonuçlar
verecekler

1
Değerler boşluk içeriyorsa elbette kullanmalısınız for f in "${fnames[@]}"; do echo $f; done(tırnak işaretleri içinde ${fnames[@]}) fnames. Ve "$f"özellikle de echo(ör . catVeya cp) den daha karmaşık bir şey yapıyorsanız kullanmalısınız . (Ve sadece yapıyor olsanız bile echo, printfyerine kullanmalısınız .)
Scott

Sanırım @ user13742 de cevaba not edilmelidir.
Fallenreaper

1

Bana göre yapmalısın ...

printf %s.txt\\n a b c

Bunu yapmadan önce OP'nin muhtemelen yankı dışında yapacak bir şeyleri olmasına rağmen bunu seviyorum.
Elder Geek

0

Kullanıcı 13742 tarafından yorumlarda belirtildiği gibi , bashve içindeki dizileri kullanabiliriz ksh:

#!/usr/bin/env bash

files_list=( "a.txt" "b.txt" "c and space.txt" )

for i in "${files_list[@]}"
do
    echo "$i"
    # do something else here,maybe
done

Ve bu şekilde çalışır:

$ ./iterate_files_array.sh                                                      
a.txt
b.txt
c and space.txt

Ancak, dash( /bin/shUbuntu'da) gibi bazı kabuklar dizileri desteklemez. Bu durumda, burada belge yapısını kullanmaya başvurabiliriz:<<

#!/bin/sh

while IFS= read -r line
do
    echo "$line"
done << EOL
one.txt
two.txt
with space.txt
EOL
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.