cara menggeser nilai array dalam bash

8

kami ingin membuat 6 folder mount point sebagai contoh

/data/sdb
/data/sdc
/data/sdd
/data/sde
/data/sdf
/data/sdg

jadi kami menulis skrip bash sederhana ini menggunakan array

folder_mount_point_list="sdb sdc sdd sde sdf sdg"

folderArray=( $folder_mount_point_list )

counter=0
for i in disk1 disk2 disk3 disk4 disk4 disk5 disk6
do
folder_name=${folderArray[counter]}
mkdir /data/$folder_name
let counter=$counter+1
done

sekarang kita ingin mengubah kode tanpa penghitung dan biarkan = $ counter = penghitung + 1

apakah mungkin untuk menggeser setiap loop array untuk mendapatkan nilai array selanjutnya?

seperti sesuatu

${folderArray[++]}
yael
sumber
1
untuk apa for i in disk1 disk2 disk3 disk4 disk4 disk5 disk6karena tidak digunakan dalam loop body?
RomanPerekhrest
1
... dan apa gunanya menggunakan penghitung? Mengapa kamu tidak lari saja for i in "your_list_goes_here"; do mkdir /data/"$i"; done?
don_crissti

Jawaban:

10

Komentar umum. Tidak masuk akal untuk mendefinisikan array seperti ini:

folder_mount_point_list="sdb sdc sdd sde sdf sdg"
folderArray=( $folder_mount_point_list )

Anda akan melakukan ini sebagai gantinya:

folderArray=(sdb sdc sdd sde sdf sdg)

Sekarang untuk pertanyaan Anda:

set -- sdb sdc sdd sde sdf sdg
for folder_name; do
    mkdir "/data/$folder_name"
done

atau

set -- sdb sdc sdd sde sdf sdg
while [ $# -gt 0 ]; do
    mkdir "/data/$1"
    shift
done
Hauke ​​Laging
sumber
dapatkah kita melakukan set untuk variabel sebagai set - $ list_of_folders (sementara list_of_folders = "sdb sdc sdd sde"
yael
@ Ya Ya, Anda dapat menggunakan set -- $list_of_folderstetapi sekali lagi: Variabel string bukan cara untuk pergi:set -- "${folders[@]}"
Hauke ​​Laging
1
mengapa kamu bahkan menggunakan set -- ....? hack itu hanya diperlukan di shell yang tidak mendukung array - tidak perlu di shell yang mendukung array. for folder_name in "${folderArray[@]}"; do ... ; donehanya itu yang dibutuhkan.
cas
hanya satu pertanyaan, apakah ada pilihan untuk melakukan sesuatu seperti - $ {folderArray [++]}
yael
@Cas itulah yang saya miliki dalam jawaban saya. Saya juga tidak mendapatkan setpendekatan ini .
PesaThe
14

Untuk menjawab pertanyaan dalam judul, Anda dapat "menggeser" array dengan notasi substring / subarray. ( shiftitu sendiri bekerja hanya dengan parameter posisi.)

$ a=(a b c d e)
$ a=("${a[@]:1}")
$ echo "${a[@]}"
b c d e

Demikian pula, untuk 'pop' item terakhir dari array: a=("${a[@]:0:${#a[@]} - 1}" )atauunset "a[${#a[@]}-1]"

Jadi jika Anda mau, Anda bisa melakukan ini:

a=(foo bar doo)
b=(123 456 789)
while [ "${#a[@]}" -gt 0 ] ; do
    echo "$a $b"
    a=("${a[@]:1}")
    b=("${b[@]:1}")
done

Tapi itu akan merusak array, jadi hanya mengindeks seperti biasa mungkin lebih baik. Atau mungkin menggunakan array asosiatif sebagai gantinya:

declare -A arr=([foo]=123 [bar]=456 [doo]=789)
ilkkachu
sumber
4

Anda dapat dengan mudah mengulang semua nilai, tidak perlu bergeser:

folderArray=(sdb sdc sdd sde sdf sdg)

for folder in "${folderArray[@]}"; do
    mkdir "/data/$folder"
done
Pesa
sumber
3

Anda tidak memerlukan loop apa pun untuk itu:

folderArray=(sdb sdc sdd sde sdf sdg)
IFS=,
eval mkdir /data/{"${folderArray[*]}"}

Kuncinya adalah bahwa jika sebuah array dikutip dua kali dengan subskrip *( "${array[*]}") ia meluas ke satu kata dengan nilai setiap elemen array dipisahkan oleh karakter pertama dari IFSvariabel. Setelah itu kami menggunakan mekanisme ekspansi brace untuk melampirkan /data/ke setiap anggota array dan evaluate semuanya.

jimmij
sumber
Kenapa begitu rumit? cd /data ; mkdir "${folderArray[@]}"Saya telah melakukan hal yang sama sebelumnya tetapi saya tidak akan dalam kasus seperti ini. Tapi +1 untuk pendekatan lanjutan.
Hauke ​​Laging,
@ HaukeLaging Ya, itu akan lebih mudah jika ada mkdirperintah. Dan bahkan array tidak diperlukan, cd /data; mkdir abc defseperti yang dilakukan orang normal. Tetapi tidak bisa sesederhana untuk tugas-tugas lain, jadi ada baiknya untuk mengetahui cara melampirkan string dengan cepat ke setiap elemen array tanpa loop.
jimmij
hanya satu pertanyaan, apakah ada pilihan untuk melakukan sesuatu seperti - $ {folderArray [++]}
yael
1
@el Anda dapat melakukan sesuatu seperti echo "${folderArray[((counter++))]}"jika Anda benar-benar menyukai pendekatan ini. Hal-hal di dalam (())dievaluasi sebagai matematika (perhatikan kurangnya $di depan counter).
jimmij
1
dan ketika Anda mulai menulis kode shell seperti itu, Anda menyadari bahwa meluangkan sedikit waktu untuk mempelajari perl atau python adalah ide yang bagus. yaitu hanya karena Anda dapat melakukan sesuatu dengan bash, tidak berarti Anda harus melakukannya .
cas