18 Pertanyaan: Memutar melalui serangkaian string di Bash?

pertanyaan dibuat di Mon, Apr 22, 2019 12:00 AM

Saya ingin menulis skrip yang loop melalui 15 string (array mungkin?) Apakah itu mungkin?

Sesuatu seperti:

 
for databaseName in listOfNames
then
  # Do something
end
    
1261
18 Jawaban                              18                         

Anda dapat menggunakannya seperti ini:

 
## 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

Juga berfungsi untuk deklarasi array multi-baris

 
declare -a arr=("element1" 
                "element2" "element3"
                "element4"
                )
    
2019
2016-11-14 07: 53: 22Z
  1. entah bagaimana "" sekitar $i diperlukan untuk mengakses setiap elemen array, dapatkah Anda menjelaskan mengapa atau menunjuk ke beberapa materi yang dapat saya baca untuk memahaminya? Terima kasih banyak!
    2014-09-26 16: 22: 55Z
  2. Dalam BASH lebih aman untuk mengutip variabel menggunakan "" untuk kasus-kasus ketika $i mungkin berisi spasi putih atau shell karakter yang dapat diperluas.
    2014-09-26 16: 29: 23Z
  3. Itu berfungsi dengan spasi di elemen jika dikutip seperti ditunjukkan di atas. Lebih baik Anda mengujinya sendiri.
    2014-11-12 10: 19: 53Z
  4. Apa kelebihan dari declare -a? Tidak bisakah saya melakukan sesuatu yang lebih sederhana, seperti arr=("element1" "element2" "element3")?
    2016-01-19 14: 15: 14Z
  5. declare atau typeset adalah cara eksplisit untuk mendeklarasikan variabel dalam skrip shell.
    2016-01-19 15: 38: 17Z

Itu mungkin, tentu saja.

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

Lihat Bash Loops untuk, sementara dan sampai untuk detail .

    
671
2016-12-12 17: 27: 05Z
  1. Apa masalah dengan pendekatan ini? Dalam kasus sederhana, tampaknya berhasil dan, kemudian, lebih intuitif daripada jawaban @ anubhava.
    2012-08-30 11: 54: 18Z
  2. Ini berfungsi baik dengan substitusi perintah, misalnya for year in $(seq 2000 2013).
    2013-05-20 14: 53: 40Z
  3. Masalahnya adalah ia bertanya tentang iterasi melalui array.
    2013-07-18 23: 00: 18Z
  4. Pendekatan 'mendeklarasikan' bekerja paling baik jika Anda harus mengulangi array yang sama di lebih dari satu tempat. Pendekatan ini lebih bersih tetapi kurang fleksibel.
    2014-01-03 10: 21: 08Z
  5. Mengapa bukan ini # 1? Ini lebih bersih, dan Anda dapat dengan mudah menggunakan kembali array hanya dengan mengatur string, mis., DATABASES="a b c d e f".
    2014-07-02-02 21: 42: 34Z

Tidak satu pun dari jawaban itu termasuk penghitung ...

 
#!/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

Output:

 
1  /  3  :  one
2  /  3  :  two
3  /  3  :  three
    
172
2015-07-09 05: 24: 39Z
  1. Ini harus menjadi jawaban yang diterima, adalah satu-satunya yang berfungsi ketika elemen array mengandung spasi.
    2014-11-12 09: 40: 10Z
  2. Anda harus memulai i pada 0 untuk kewarasan, tentu saja.
    2015-02-03 19: 32: 34Z
  3. Gema di akhir adalah buggy. Anda tidak perlu mengutip konstanta, Anda perlu mengutip ekspansi, atau dapat dengan aman mengutip keduanya sebagai berikut: echo "$i / ${arraylength} : ${array[$i-1]}" - jika tidak, jika $i Anda berisi bola dunia, ia akan diperluas, jika mengandung tab, maka akan diubah menjadi spasi, dll.
    2016-07-09 15: 02: 26Z
  4. @ bzeaman, tentu - tetapi jika Anda ceroboh tentang hal-hal seperti itu maka diperlukan analisis kontekstual (seperti yang baru saja Anda lakukan) untuk membuktikan sesuatu yang benar, dan analisis ulang jika konteks itu berubah atau kode digunakan kembali di tempat yang berbeda atau untuk alasan apa pun lainnya, aliran kontrol yang tidak terduga dimungkinkan. Tulis dengan cara yang kuat dan benar terlepas dari konteksnya.
    2016-09-02 14: 57: 57Z
  5. Ini tidak akan berfungsi untuk array yang jarang, mis. jika array tersebut elemen yang hilang. Misalnya, jika Anda memiliki elemen array A [1] = 'xx', A [4] = 'yy' dan A [9] = 'zz', panjangnya akan 3 dan loop tidak akan memproses semua elemen .
    2017-12-12 09: 18: 37Z

Dengan semangat yang sama dengan jawaban 4ndrew:

 
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. Tidak ada spasi putih dalam nama:

 
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

  1. Pada contoh kedua, menggunakan listOfNames="RA RB R C RD" memiliki output yang sama.

Cara lain untuk memasukkan data meliputi:

Baca dari stdin

 
# 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 "pemisah bidang ke baris" [ 1 ] pembatas dapat ditentukan dalam skrip untuk memungkinkan spasi putih lainnya (yaitu IFS='\n', atau untuk MacOS IFS='\r')
  2. Saya juga suka jawaban yang diterima :) - Saya sudah memasukkan snippet ini sebagai cara bermanfaat lainnya yang juga menjawab pertanyaan.
  3. Termasuk #!/bin/bash di bagian atas file skrip menunjukkan lingkungan eksekusi.
  4. Butuh waktu berbulan-bulan untuk mencari tahu bagaimana cara membuat kode ini dengan mudah :)

Sumber Lainnya ( saat membaca loop )

    
103
2017-05-23 12: 10: 54Z
  1. Ini menciptakan kesan bahwa eol digunakan sebagai pemisah string dan, oleh karena itu, spasi putih diizinkan dalam string. Namun, string dengan spasi putih lebih jauh dipisahkan menjadi substring, yang sangat sangat buruk. Saya pikir jawaban ini stackoverflow.com/a/23561892/1083704 lebih baik.
    2014-07-11 09: 02: 36Z
  2. @ Val, saya menambahkan komentar kode dengan referensi ke IFS. (Untuk semua orang, IFS memungkinkan seseorang menentukan pembatas tertentu, yang memungkinkan spasi putih lainnya untuk dimasukkan dalam string tanpa dipisahkan ke dalam substring).
    2014-07-21 23: 43: 05Z
  3. Ini tidak berfungsi untuk saya. $databaseName hanya berisi seluruh daftar, dengan demikian hanya satu iterasi tunggal.
    2016-07-18 13: 04: 20Z
  4. @ AlikElzin-kilaka Jawaban saya di bawah menyelesaikan masalah ini sehingga loop dijalankan untuk setiap baris string.
    2016-10-16 22: 00: 16Z

Ya

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

Output:

 
Item1
Item2
Item3
Item4

Melewati banyak baris

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

Output:

 
Item1
Item2
Item3
Item4


Variabel daftar sederhana

 
List=( Item1 Item2 Item3 )

atau

 
List=(
      Item1 
      Item2 
      Item3
     )

Tampilkan variabel daftar:

 
echo ${List[*]}

Output:

 
Item1 Item2 Item3

Simpulkan daftar:

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

Output:

 
Item1
Item2
Item3

Buat fungsi untuk menelusuri daftar:

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

Untuk menghemat ruang; entri daftar kutipan tunggal atau ganda dan ekspansi daftar kutipan ganda:

 
List=(' Item 1 '
      ' Item 2' 
      ' Item 3'
     )
for item in "${List[@]}"; 
  do 
    echo "$item"
  done 

Output:

 
 Item 1
 Item 2
 Item 3

Menggunakan kata kunci mendeklarasikan (perintah) untuk membuat daftar, yang secara teknis disebut array:

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

Output:

 
element 1
element 2
element 3

Membuat array asosiatif. Kamus:

 
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

Output:

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

Variabel atau file CVS ke daftar .
Mengubah pemisah bidang internal dari ruang, ke apa pun yang Anda inginkan.
Pada contoh di bawah ini diubah menjadi koma

 
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

Output:

 
Item 1
Item 2
Item 3

Jika perlu memberi nomor:

 
` 

ini disebut centang kembali. Masukkan perintah di dalam kutu kembali.

 
`commend` 

Itu di sebelah nomor satu di keyboard Anda dan atau di atas tombol tab. Pada keyboard bahasa Inggris standar Amerika.

 
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

Outputnya adalah:

 
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

Menjadi lebih terbiasa dengan perilaku bashes:

Buat daftar di file

 
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

Baca file daftar ke daftar dan tampilkan

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

manual referensi baris perintah BASH: Arti khusus dari karakter atau kata-kata tertentu untuk shell.

    
88
2019-02-26 16: 13: 01Z
  1. INI SALAH. Perlu "${List[@]}" untuk menjadi benar, dengan tanda kutip . ${List[@]} salah. ${List[*]} salah. Coba List=( "* first item *" "* second item *" ) - Anda akan mendapatkan perilaku yang benar untuk for item in "${List[@]}"; do echo "$item"; done, tetapi tidak dari varian lain.
    2018-05-04 19: 36: 25Z
  2. Ya karakter khusus dapat diartikan, yang mungkin atau mungkin tidak diinginkan. Saya memperbarui jawaban untuk disertakan.
    2018-05-27 10: 57: 21Z
  3. Saya masih sangat menyarankan menunjukkan pendekatan yang lebih benar /kuat pertama . Orang sering mengambil jawaban pertama yang kelihatannya akan bekerja; jika jawaban itu memiliki peringatan tersembunyi, mereka hanya dapat mengekspos diri mereka nanti. (Bukan hanya wildcard yang rusak karena kurangnya penawaran; List=( "first item" "second item" ) akan dipecah menjadi first, item, second, item juga).
    2018-05-27 15: 13: 24Z
  4. Anda mungkin juga mempertimbangkan untuk menghindari penggunaan contoh yang dapat menyebabkan orang mem-parsing output ls, bertentangan dengan praktik terbaik .
    2018-05-27 15: 16: 00Z
  5. Anda menyangkal klaim yang tidak pernah saya buat. Saya cukup akrab dengan semantik kutipan bash - lihat stackoverflow.com/tags/bash/topusers
    2018-05-31 23: 59: 18Z

Anda dapat menggunakan sintaks ${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
    
39
2017-10-25 05: 36: 23Z

Ini juga mudah dibaca:

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

#Loop
for Path in "${FilePath[@]}"
do
    echo "$Path"
done
    
20
2015-07-03 04: 03: 53Z
  1. Yang ini jelas dan bekerja untuk saya (termasuk dengan spasi dan substitusi variabel dalam elemen array FilePath) hanya ketika saya mengatur variabel IFS dengan benar sebelum i> definisi array FilePath: IFS=$'\n' Ini juga dapat digunakan untuk solusi lain dalam skenario ini.
    2016-01-22 12: 41: 49Z

Terkejut bahwa belum ada yang memposting ini - jika Anda memerlukan indeks elemen saat Anda sedang menjelajahi array, Anda dapat melakukan ini:

 
arr=(foo bar baz)

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

Output:

 
0 foo
1 bar
2 baz

Saya menemukan ini jauh lebih elegan daripada gaya for-loop "tradisional" (for (( i=0; i<${#arr[@]}; i++ ))).

(${!arr[@]} dan $i tidak perlu dikutip karena itu hanya angka; beberapa akan menyarankan mengutipnya, tapi itu hanya preferensi pribadi.)

    
18
2018-08-10 22: 27: 16Z

Array implisit untuk skrip atau fungsi:

Selain jawaban yang benar anubhava : Jika sintaks dasar untuk loop adalah:

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

ada kasus khusus dalam :

Saat menjalankan skrip atau fungsi, argumen yang dilewatkan di baris perintah akan ditetapkan ke $@ variabel array, Anda dapat mengakses dengan $1, $2, $3, dan sebagainya.

Ini dapat diisi (untuk pengujian) oleh

 
set -- arg1 arg2 arg3 ...

A loop di atas array ini dapat ditulis dengan sederhana:

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

Catatan bahwa karya yang dipesan in tidak ada dan tidak ada nama array juga!

Contoh:

 
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: ....

Perhatikan bahwa ini sama dengan

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

Lalu ke dalam skrip :

 
#!/bin/bash

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

Simpan ini dalam skrip myscript.sh, chmod +x myscript.sh, lalu

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

Sama dengan fungsi :

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

Lalu

 
myfunc item1 tiem2 time3
Working about 'item1'.
Working about 'tiem2'.
Working about 'time3'.
    
8
2017-12-05 08: 01: 30Z
 
listOfNames="db_one db_two db_three"
for databaseName in $listOfNames
do
  echo $databaseName
done

atau hanya

 
for databaseName in db_one db_two db_three
do
  echo $databaseName
done
    
6
2016-08-25 00: 20: 03Z

Array deklarasi tidak berfungsi untuk Korn shell. Gunakan contoh di bawah ini untuk shell Korn:

 
promote_sla_chk_lst="cdi xlob"

set -A promote_arry $promote_sla_chk_lst

for i in ${promote_arry[*]};
    do
            echo $i
    done
    
5
2017-06-04 21: 51: 51Z
  1. coba penyorot kode di editor untuk membuat kode Anda terlihat bagus.
    2012-11-02 19: 39: 26Z
  2. Senang tahu, tetapi pertanyaan ini tentang bash.
    2013-05-20 14: 47: 48Z
  3. Lotsa bug di sini. Tidak dapat memiliki entri daftar dengan spasi, tidak dapat memiliki entri daftar dengan karakter glob. for i in ${foo[*]} pada dasarnya selalu hal yang salah - for i in "${foo[@]}" adalah bentuk yang mempertahankan batas-batas daftar asli dan mencegah ekspansi global. Dan gema harus berupa echo "$i"
    2016-07-09 15: 00: 07Z

Cara sederhana:

 
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}
    
5
2018-09-02 15: 36: 01Z

Ini mirip dengan jawaban pengguna2533809, tetapi setiap file akan dieksekusi sebagai perintah terpisah.

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

while read -r line; do
    echo line: "$line"
done <<< "$names"
    
4
2016-10-16 21: 59: 34Z

Jika Anda menggunakan Korn shell, ada " set -A databaseName ", selain itu ada " menyatakan -a databaseName "

Untuk menulis skrip yang berfungsi pada semua shell,

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

done

Ini harusnya bekerja pada semua shell.

    
3
2014-09-25 08: 32: 53Z
  1. Tidak, tidak: $ bash --version GNU bash, versi 4.3.33 (0) -release (amd64-portbld-freebsd10.0) $ set -A databaseName=("db1" "db2" ....) || declare -a databaseName=("db1" "db2" ....) bash: kesalahan sintaksis dekat token tak terduga `('
    2017-01-17 19: 47: 12Z

Coba ini. Ini berfungsi dan diuji.

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

# For accessing with the echo command: echo ${array[0]}, ${array[1]}
    
2
2017-06-04 22: 01: 28Z
  1. Ini sebenarnya tidak berfungsi dengan benar. Coba array=( "hello world" ), atau arrray=( "*" ); pada kasus pertama, ia akan mencetak hello dan world secara terpisah, pada kasus kedua ia akan mencetak daftar file alih-alih *
    2016-07-09 14: 55: 53Z
  2. ... sebelum memanggil sesuatu yang "diuji" di shell, pastikan untuk memeriksa kasing sudut, di mana spasi putih dan gumpalan keduanya berada di antara keduanya.
    2016-07-09 14: 58: 13Z

Kemungkinan baris pertama dari setiap skrip /sesi Bash:

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

Gunakan misalnya .:

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

Dapat mempertimbangkan: echo mengartikan -e sebagai opsi di sini

    
2
2017-06-04 22: 02: 27Z

Perulangan baris tunggal,

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

Anda akan mendapatkan output seperti ini,

 
db_a
db_b
db_c
    
2
2017-06-27 13: 16: 43Z

Saya mengulangi array proyek saya untuk pembaruan git pull:

 
#!/bin/sh
projects="
web
ios
android
"
for project in $projects do
    cd  $HOME/develop/$project && git pull
end
    
- 3
2017-06-04 22: 02: 58Z
  1. Sementara cuplikan kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan sangat membantu meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, dan orang-orang itu mungkin tidak tahu alasan untuk saran kode Anda. Tolong juga cobalah untuk tidak membuat kerumunan kode Anda dengan komentar penjelasan, ini mengurangi keterbacaan kode dan penjelasan!
    2016-12-08 08: 37: 13Z
sumber ditempatkan sini