Làm thế nào để thay đổi giá trị mảng trong bash


8

chúng tôi muốn xây dựng 6 thư mục điểm gắn kết làm ví dụ

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

Vì vậy, chúng tôi đã viết kịch bản bash đơn giản này bằng cách sử dụng mảng

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

bây giờ chúng tôi muốn thay đổi mã mà không có bộ đếmlet = $ counter = counter + 1

Có thể dịch chuyển từng vòng lặp mảng để có được giá trị mảng tiếp theo không?

như một cái gì đó như

${folderArray[++]}

1
những gì for i in disk1 disk2 disk3 disk4 disk4 disk5 disk6cho nó không được sử dụng trong cơ thể vòng lặp?
RomanPerekhrest

1
... Và quan điểm của việc sử dụng một bộ đếm là gì? Tại sao bạn không đơn giản chạy for i in "your_list_goes_here"; do mkdir /data/"$i"; done?
don_crissti

Câu trả lời:


10

Một nhận xét chung. Không có nghĩa gì khi định nghĩa một mảng như thế này:

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

Bạn sẽ làm điều này thay vào đó:

folderArray=(sdb sdc sdd sde sdf sdg)

Bây giờ đến câu hỏi của bạn:

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

hoặc là

set -- sdb sdc sdd sde sdf sdg
while [ $# -gt 0 ]; do
    mkdir "/data/$1"
    shift
done

chúng ta có thể thực hiện cài đặt cho biến như set - $ list_of_ Folders (while list_of_ Folders = "sdb sdc sdd sde"
yael 31/12/17

@yael Có, bạn có thể sử dụng set -- $list_of_foldersnhưng một lần nữa: Biến chuỗi không phải là hướng đi:set -- "${folders[@]}"
Hauke ​​Laging 31/12/17

1
tại sao bạn thậm chí sử dụng set -- ....? rằng hack chỉ cần thiết trong các shell không hỗ trợ mảng - không cần nó trong shell hỗ trợ mảng. for folder_name in "${folderArray[@]}"; do ... ; donelà tất cả những gì cần thiết
cas

chỉ một câu hỏi, có sự lựa chọn nào để làm một cái gì đó như - $ {thư mụcArray [++]}
yael

@cas đó là những gì tôi có trong câu trả lời của tôi. Tôi cũng không có được setcách tiếp cận này .
PesaThe 31/12/17

14

Để trả lời câu hỏi trong tiêu đề, bạn có thể "dịch chuyển" một mảng với ký hiệu chuỗi con / chuỗi con. ( shiftchính nó hoạt động với chỉ các tham số vị trí.)

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

Tương tự, để 'bật' mục cuối cùng ra khỏi mảng: a=("${a[@]:0:${#a[@]} - 1}" )hoặcunset "a[${#a[@]}-1]"

Vì vậy, nếu bạn muốn, bạn có thể làm điều này:

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

Nhưng nó bỏ qua các mảng, vì vậy chỉ cần lập chỉ mục như bình thường có thể tốt hơn. Hoặc có thể sử dụng một mảng kết hợp thay thế:

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

4

Bạn chỉ có thể lặp qua tất cả các giá trị, không cần dịch chuyển:

folderArray=(sdb sdc sdd sde sdf sdg)

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

3

Bạn không cần bất kỳ vòng lặp nào cho điều đó:

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

Thủ thuật là nếu một mảng được trích dẫn kép với subscript *( "${array[*]}") thì nó sẽ mở rộng thành một từ duy nhất với giá trị của mỗi phần tử mảng được phân tách bằng ký tự đầu tiên của IFSbiến. Sau đó, chúng tôi sử dụng cơ chế mở rộng cú đúp để gắn /data/vào từng thành viên mảng và evaluate toàn bộ.


Sao lại phức tạp thế? cd /data ; mkdir "${folderArray[@]}"Tôi đã làm như vậy trước đây nhưng tôi sẽ không trong trường hợp như thế này. Nhưng +1 cho cách tiếp cận nâng cao.
Hauke ​​Laging

@HaukeLaging Có, điều đó sẽ đơn giản hơn trong trường hợp mkdirlệnh. Và thậm chí mảng không cần thiết, giống cd /data; mkdir abc defnhư người bình thường sẽ làm. Nhưng không thể đơn giản cho các tác vụ khác, vì vậy thật tốt khi biết cách nhanh chóng đính kèm một chuỗi vào mỗi phần tử mảng mà không cần một vòng lặp.
jimmij

chỉ một câu hỏi, có sự lựa chọn nào để làm một cái gì đó như - $ {thư mụcArray [++]}
yael

1
@yael Bạn có thể làm một cái gì đó như echo "${folderArray[((counter++))]}"nếu bạn thực sự thích phương pháp này. Những thứ bên trong (())được đánh giá là toán học (thông báo thiếu $ở phía trước counter).
jimmij

1
và khi bạn bắt đầu viết mã shell như vậy, bạn nhận ra rằng dành một ít thời gian để học perl hoặc python sẽ là một ý tưởng tốt. tức là chỉ vì bạn có thể làm gì đó với bash, không có nghĩa là bạn nên làm .
cas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.