Bash'de bir dizi diziye mi döneceksiniz?


1501

15 dizeleri (dizi muhtemelen?) Üzerinden döngüler bir komut dosyası yazmak istiyorum Bu mümkün mü?

Gibi bir şey:

for databaseName in listOfNames
then
  # Do something
end

Yanıtlar:


2389

Bu şekilde kullanabilirsiniz:

## declare an array variable
declare -a arr=("element1" "element2" "element3")

## now loop through the above array
for i in "${arr[@]}"
do
   echo "$i"
   # or do whatever with individual element of the array
done

# You can access them using echo "${arr[0]}", "${arr[1]}" also

Ayrıca çok satırlı dizi bildirimi için de çalışır

declare -a arr=("element1" 
                "element2" "element3"
                "element4"
                )

776

Tabii ki bu mümkün.

for databaseName in a b c d e f; do
  # do something like: echo $databaseName
done 

Ayrıntılar için Bash Loops'a, süre ve sonrasına bakın.


18
Bu yaklaşımla ilgili sorun nedir? Basit durumlarda işe yarıyor gibi görünüyor ve o zaman @ anubhava'nın cevabından daha sezgisel.
Dr.Jan-Philip Gehrcke

17
Bu özellikle komut ikamesi ile iyi çalışır, örn for year in $(seq 2000 2013).
Brad Koch

23
Sorun şu ki, o bir dizi üzerinden yineleme hakkında sordu.
mgalgs

20
Aynı dizide birden fazla yerde yineleme yapmanız gerekiyorsa, 'bildir' yaklaşımı en iyi sonucu verir. Bu yaklaşım daha temiz ama daha az esnektir.
StampyCode

15
Neden bu # 1 değil? Daha temiz ve sadece bir dize ayarlayarak diziyi kolayca yeniden kullanabilirsiniz, yani DATABASES="a b c d e f".
Nerdmaster

201

Bu cevapların hiçbirinde sayaç yok ...

#!/bin/bash
## declare an array variable
declare -a array=("one" "two" "three")

# get length of an array
arraylength=${#array[@]}

# use for loop to read all values and indexes
for (( i=1; i<${arraylength}+1; i++ ));
do
  echo $i " / " ${arraylength} " : " ${array[$i-1]}
done

Çıktı:

1  /  3  :  one
2  /  3  :  two
3  /  3  :  three

7
Bu, kabul edilen yanıt olmalıdır, dizi öğeleri boşluk içerdiğinde çalışan tek yanıttır.
jesjimher

1
Bu sadece bir sayaç ile örneğin çıktısı uğruna. Bunu değiştirmek de oldukça önemsiz ve aynı şekilde çalışıyor.
caktux

7
Sondaki yankı buggy. Sabitleri alıntılamanıza gerek yoktur, genişletmeleri alıntılamanız gerekir ya da her ikisini de güvenli bir şekilde aşağıdaki gibi alıntılayabilirsiniz: echo "$i / ${arraylength} : ${array[$i-1]}"- aksi takdirde, $ibir glob içeriğiniz varsa genişletilir, bir sekme içeriyorsa, bir alan, vs.
Charles Duffy

10
@bzeaman, tabii ki - ancak bu tür şeyler konusunda özensizseniz, doğru bir şeyi kanıtlamak için bağlamsal analiz (az önce yaptığınız gibi) ve bu bağlam değişirse veya kod farklı bir yerde veya kod için tekrar kullanılırsa yeniden analiz gerektirir. başka bir nedenden dolayı beklenmedik bir kontrol akışı mümkündür. Sağlam bir yol yazın ve bağlamdan bağımsız olarak doğrudur.
Charles Duffy

5
Bu, seyrek bir dizi için çalışmaz, yani dizi eksik öğeler varsa. Örneğin, A [1] = 'xx', A [4] = 'yy' ve A [9] = 'zz' dizi öğeleriniz varsa, uzunluk 3 olur ve döngü tüm öğeleri işlemez .
Bay Ed

145

Evet

for Item in Item1 Item2 Item3 Item4 ;
  do
    echo $Item
  done

Çıktı:

Item1
Item2
Item3
Item4

Mekanları korumak için; tek veya çift teklif listesi girişleri ve çift teklif listesi genişletmeleri.

for Item in 'Item 1' 'Item 2' 'Item 3' 'Item 4' ;
  do
    echo "$Item"
  done

Çıktı:

Item 1
Item 2
Item 3
Item 4

Birden çok satır üzerinden liste yapmak için

for Item in Item1 \
            Item2 \
            Item3 \
            Item4
  do
    echo $Item
  done

Çıktı:

Item1
Item2
Item3
Item4


Basit liste değişkeni

List=( Item1 Item2 Item3 )

veya

List=(
      Item1 
      Item2 
      Item3
     )

Liste değişkenini görüntüle:

echo ${List[*]}

Çıktı:

Item1 Item2 Item3

Listede dolaşın:

for Item in ${List[*]} 
  do
    echo $Item 
  done

Çıktı:

Item1
Item2
Item3

Listede ilerlemek için bir işlev oluşturun:

Loop(){
  for item in ${*} ; 
    do 
      echo ${item} 
    done
}
Loop ${List[*]}

Teknik olarak dizi olarak adlandırılan listeyi oluşturmak için declare anahtar sözcüğünü (command) kullanma:

declare -a List=(
                 "element 1" 
                 "element 2" 
                 "element 3"
                )
for entry in "${List[@]}"
   do
     echo "$entry"
   done

Çıktı:

element 1
element 2
element 3

İlişkilendirilebilir bir dizi oluşturma. Bir sözlük:

declare -A continent

continent[Vietnam]=Asia
continent[France]=Europe
continent[Argentina]=America

for item in "${!continent[@]}"; 
  do
    printf "$item is in ${continent[$item]} \n"
  done

Çıktı:

 Argentina is in America
 Vietnam is in Asia
 France is in Europe

Bir listeye CVS değişkenleri veya dosyaları .
Dahili alan ayırıcısını bir boşluktan, istediğiniz bir şeye değiştirmek.
Aşağıdaki örnekte virgülle değiştirilmiştir

List="Item 1,Item 2,Item 3"
Backup_of_internal_field_separator=$IFS
IFS=,
for item in $List; 
  do
    echo $item
  done
IFS=$Backup_of_internal_field_separator

Çıktı:

Item 1
Item 2
Item 3

Onları numaralandırmanız gerekiyorsa:

` 

buna arka kene denir. Komutu arka kenelere koyun.

`commend` 

Klavyenizde bir numara yanında veya sekme tuşunun üstünde. Standart bir Amerikan İngilizcesi klavyesinde.

List=()
Start_count=0
Step_count=0.1
Stop_count=1
for Item in `seq $Start_count $Step_count $Stop_count`
    do 
       List+=(Item_$Item)
    done
for Item in ${List[*]}
    do 
        echo $Item
    done

Çıktı:

Item_0.0
Item_0.1
Item_0.2
Item_0.3
Item_0.4
Item_0.5
Item_0.6
Item_0.7
Item_0.8
Item_0.9
Item_1.0

Bash davranışı hakkında daha fazla bilgi sahibi olmak:

Dosyada liste oluşturma

cat <<EOF> List_entries.txt
Item1
Item 2 
'Item 3'
"Item 4"
Item 7 : *
"Item 6 : * "
"Item 6 : *"
Item 8 : $PWD
'Item 8 : $PWD'
"Item 9 : $PWD"
EOF

Liste dosyasını bir listeye okuyun ve görüntüleyin

List=$(cat List_entries.txt)
echo $List
echo '$List'
echo "$List"
echo ${List[*]}
echo '${List[*]}'
echo "${List[*]}"
echo ${List[@]}
echo '${List[@]}'
echo "${List[@]}"

BASH komut satırı referans kılavuzu: Kabuğa belirli karakterlerin veya kelimelerin özel anlamı.


7
BU YANLIŞ. Tırnaklarla"${List[@]}" doğru olmak gerekiyor . Hata. Hata. Deneyin - başka bir varyanttan değil, doğru davranış elde edersiniz . ${List[@]}${List[*]}List=( "* first item *" "* second item *" )for item in "${List[@]}"; do echo "$item"; done
Charles Duffy

Evet, özel karakterler yorumlanabilir, bu istenebilir veya istenmeyebilir. Cevabı içerecek şekilde güncelledim.
FireInTheSky

2
Öncelikle daha doğru / sağlam yaklaşımı göstermenizi şiddetle tavsiye ediyorum . İnsanlar genellikle işe yarayacak gibi görünen ilk cevabı alırlar; bu cevabın gizli uyarıları varsa, ancak daha sonra kendilerini gösterebilirler. (; Sadece alıntı yetersizliği kırık joker değil List=( "first item" "second item" )bölünür olacak first, item, second, itemyanı).
Charles Duffy

Ayrıca , en iyi uygulamalara aykırı olarakls , insanların çıktıları ayrıştırmasına neden olabilecek bir örnek kullanmaktan kaçınmayı da düşünebilirsiniz .
Charles Duffy

1
Hiç yapmadığım iddiaları reddediyorsun. Bash'ın alıntı anlambilimine oldukça aşinayım - bkz. Stackoverflow.com/tags/bash/topusers
Charles Duffy

108

4. cevabın cevabı ile aynı ruhla:

listOfNames="RA
RB
R C
RD"

# To allow for other whitespace in the string:
# 1. add double quotes around the list variable, or
# 2. see the IFS note (under 'Side Notes')

for databaseName in "$listOfNames"   #  <-- Note: Added "" quotes.
do
  echo "$databaseName"  # (i.e. do action / processing of $databaseName here...)
done

# Outputs
# RA
# RB
# R C
# RD

B. İsimlerdeki boşluk yok:

listOfNames="RA
RB
R C
RD"

for databaseName in $listOfNames  # Note: No quotes
do
  echo "$databaseName"  # (i.e. do action / processing of $databaseName here...)
done

# Outputs
# RA
# RB
# R
# C
# RD

notlar

  1. İkinci örnekte, kullanma listOfNames="RA RB R C RD"aynı çıktıya sahiptir.

Veri getirmenin diğer yolları şunlardır:

Stdin'den okuyun

# line delimited (each databaseName is stored on a line)
while read databaseName
do
  echo "$databaseName"  # i.e. do action / processing of $databaseName here...
done # <<< or_another_input_method_here
  1. Bash IFS [ "hattına alan ayırıcı" 1 ] sınırlayıcı diğer boşluk sağlamak için komut belirtilebilir (yani IFS='\n', ya da MacOS IFS='\r')
  2. Kabul edilen yanıtı da seviyorum :) - Bu parçacıkları, soruyu cevaplayan diğer yararlı yollar olarak ekledim.
  3. #!/bin/bashKomut dosyasının üst kısmına eklemek yürütme ortamını gösterir.
  4. Bunu nasıl kodlayacağımı anlamak aylar sürdü :)

Diğer Kaynaklar ( okuma döngüsü sırasında )


Bu, eol'ün dize ayırıcıları olarak kullanıldığı izlenimini yaratır ve bu nedenle dizelerde boşluklara izin verilir. Bununla birlikte, beyaz boşluklu dizeler alt dizelere ayrılır, bu da çok çok kötüdür. Bu cevabın stackoverflow.com/a/23561892/1083704 daha iyi olduğunu düşünüyorum .
Val

1
@Val, ben referans ile kod yorum ekledi IFS. (Herkes için, IFSdiğer boşlukların alt dizelere ayrılmadan dizelere eklenmesine izin veren belirli bir sınırlayıcı belirtelim).
user2533809

7
Bu benim için işe yaramıyor. $databaseNamesadece tüm listeyi içerir, böylece sadece tek bir yineleme yapar.
AlikElzin-kilaka

@ AlikElzin-kilaka Aşağıdaki cevabım döngüyü dizenin her satırı için çalışacak şekilde çözüyor.
Jamie

42

Sözdizimini kullanabilirsiniz. ${arrayName[@]}

#!/bin/bash
# declare an array called files, that contains 3 values
files=( "/etc/passwd" "/etc/group" "/etc/hosts" )
for i in "${files[@]}"
do
    echo "$i"
done

31

Henüz kimsenin bunu yayınlamamasına şaşırdım - dizi boyunca döngü yaparken öğelerin dizinlerine ihtiyacınız varsa, bunu yapabilirsiniz:

arr=(foo bar baz)

for i in ${!arr[@]}
do
    echo $i "${arr[i]}"
done

Çıktı:

0 foo
1 bar
2 baz

Bunu "geleneksel" for-döngüsü stilinden ( for (( i=0; i<${#arr[@]}; i++ ))) çok daha zarif buluyorum .

( ${!arr[@]}ve $isadece sayı olduğu için alıntılanmanıza gerek yoktur; bazıları yine de bunları alıntılamayı önerir, ancak bu sadece kişisel tercihtir.)


2
Bu gerçekten seçilen cevap olmalı. 1: Basit ve okunması kolay. 2: Boşluğu doğru işler, IFS saçmalıklarına engel olmaz. 3: Seyrek dizileri doğru şekilde işler.
mrm

20

Bunu okumak da kolaydır:

FilePath=(
    "/tmp/path1/"    #FilePath[0]
    "/tmp/path2/"    #FilePath[1]
)

#Loop
for Path in "${FilePath[@]}"
do
    echo "$Path"
done

4
Bu açık ve benim için çalıştı (boşluklar ve FilePath dizi öğelerinde değişken ikamesi dahil) yalnızca IFS değişkenini FilePath dizi tanımından önce doğru ayarladığımda : IFS=$'\n' Bu, bu senaryoda diğer çözümler için de işe yarayabilir.
Alan Forsyth

8

Komut dosyası veya işlevler için örtük dizi:

Anubhava'nın doğru cevabına ek olarak : Döngü için temel sözdizimi ise:

for var in "${arr[@]}" ;do ...$var... ;done

Bir var özel durumda:

Bir komut dosyası veya bir işlevi çalıştırırken, argümanlar komut satırlarından sonunda geçirilmesi atanacak $@dizi değişkeni, sen erişebileceğiniz $1, $2, $3, vb.

Bu, (test için) tarafından doldurulabilir

set -- arg1 arg2 arg3 ...

Bu dizi üzerinden bir döngü basitçe yazılabilir:

for item ;do
    echo "This is item: $item."
  done

Not ayrılmış çalışma olduğunu inmevcut değildir ve hiçbir dizi adı çok!

Örneklem:

set -- arg1 arg2 arg3 ...
for item ;do
    echo "This is item: $item."
  done
This is item: arg1.
This is item: arg2.
This is item: arg3.
This is item: ....

Bunun aynı olduğunu unutmayın

for item in "$@";do
    echo "This is item: $item."
  done

Sonra bir komut dosyasına :

#!/bin/bash

for item ;do
    printf "Doing something with '%s'.\n" "$item"
  done

Bir komut kaydet myscript.sh, chmod +x myscript.shsonra,

./myscript.sh arg1 arg2 arg3 ...
Doing something with 'arg1'.
Doing something with 'arg2'.
Doing something with 'arg3'.
Doing something with '...'.

Bir fonksiyonda aynı :

myfunc() { for item;do cat <<<"Working about '$item'."; done ; }

Sonra

myfunc item1 tiem2 time3
Working about 'item1'.
Working about 'tiem2'.
Working about 'time3'.

7
listOfNames="db_one db_two db_three"
for databaseName in $listOfNames
do
  echo $databaseName
done

ya da sadece

for databaseName in db_one db_two db_three
do
  echo $databaseName
done

7

Basit yol :

arr=("sharlock"  "bomkesh"  "feluda" )  ##declare array

len=${#arr[*]}  # it returns the array length

#iterate with while loop
i=0
while [ $i -lt $len ]
do
    echo ${arr[$i]}
    i=$((i+1))
done


#iterate with for loop
for i in $arr
do
  echo $i
done

#iterate with splice
 echo ${arr[@]:0:3}

6

Declare dizisi Korn kabuğu için çalışmaz. Korn kabuğu için aşağıdaki örneği kullanın:

promote_sla_chk_lst="cdi xlob"

set -A promote_arry $promote_sla_chk_lst

for i in ${promote_arry[*]};
    do
            echo $i
    done

2
kodunuzun iyi görünmesi için düzenleyicideki kod vurgulayıcıyı deneyin.
güvercin

5
Bilmek güzel, ama bu soru bash hakkında.
Brad Koch

1
Lotsa böcek burada. Boşluk içeren liste girişleri olamaz, glob karakterli liste girişleri olamaz. for i in ${foo[*]}temelde her zaman yanlış şeydir - for i in "${foo[@]}"orijinal listenin sınırlarını koruyan ve glob genişlemesini önleyen formdur. Ve yankı olması gerekiyorecho "$i"
Charles Duffy

4

Bu user2533809'un cevabına benzer, ancak her dosya ayrı bir komut olarak yürütülür.

#!/bin/bash
names="RA
RB
R C
RD"

while read -r line; do
    echo line: "$line"
done <<< "$names"

3

Korn kabuğu kullanıyorsanız, " set -A databaseName ", başka bir deyim var: " declare -a databaseName "

Tüm kabuklarda çalışan bir senaryo yazmak için,

 set -A databaseName=("db1" "db2" ....) ||
        declare -a databaseName=("db1" "db2" ....)
# now loop 
for dbname in "${arr[@]}"
do
   echo "$dbname"  # or whatever

done

Tüm mermiler üzerinde çalışması gerekir.


3
Hayır, değil: $ bash --versionGNU bash, sürüm 4.3.33 (0) -çalışma (amd64-portbld-freebsd10.0) $ set -A databaseName=("db1" "db2" ....) || declare -a databaseName=("db1" "db2" ....)bash: beklenmedik belirtecin yanında sözdizimi hatası `` (''
Bernie Reiter

2

Bunu dene. Çalışıyor ve test ediliyor.

for k in "${array[@]}"
do
    echo $k
done

# For accessing with the echo command: echo ${array[0]}, ${array[1]}

3
Bu aslında düzgün çalışmıyor. Deneyin array=( "hello world" )veya arrray=( "*" ); ilk durumda yazdıracak hellove worldayrı ayrı, ikincisinde bunun yerine bir dosya listesi yazdıracak*
Charles Duffy

6
... kabukta "test edilmiş" bir şey çağırmadan önce, boşluk ve globların her ikisinin de olduğu köşe kutularını kontrol ettiğinizden emin olun.
Charles Duffy

2

Her Bash betiğinin / oturumunun olası ilk satırı:

say() { for line in "${@}" ; do printf "%s\n" "${line}" ; done ; }

Örneğin kullanın:

$ aa=( 7 -4 -e ) ; say "${aa[@]}"
7
-4
-e

Düşünebilir: burada seçenek olarak echoyorumlar-e


2

Tek satır döngü,

 declare -a listOfNames=('db_a' 'db_b' 'db_c')
 for databaseName in ${listOfNames[@]}; do echo $databaseName; done;

böyle bir çıktı alacaksınız,

db_a
db_b
db_c

2

Bunun için gerçekten ihtiyacım olan şey şuydu:

for i in $(the_array); do something; done

Örneğin:

for i in $(ps -aux | grep vlc  | awk '{ print $2 }'); do kill -9 $i; done

(Tüm işlemleri adlarında vlc ile öldürür)


1

Bir git pullgüncelleme için projelerimin bir dizi üzerinden döngü :

#!/bin/sh
projects="
web
ios
android
"
for project in $projects do
    cd  $HOME/develop/$project && git pull
end

7
Bu kod snippet'i soruyu çözebilir, ancak bir açıklama da dahil olmak üzere , yayınınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın. Lütfen kodunuzu açıklayıcı yorumlarla doldurmamaya çalışın, bu hem kodun hem de açıklamaların okunabilirliğini azaltır!
kayess
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.