Chuyển đổi các đối số dòng lệnh thành một mảng trong Bash


160

Làm cách nào để chuyển đổi các đối số dòng lệnh thành một mảng script bash?

Tôi muốn lấy cái này:

./something.sh arg1 arg2 arg3

và chuyển đổi nó thành

myArray=( arg1 arg2 arg3 )

để tôi có thể sử dụng myArray để sử dụng thêm trong tập lệnh.

Bài viết SO trước đây đã đến gần, nhưng không đi sâu vào cách tạo một mảng: Làm thế nào để tôi phân tích các đối số dòng lệnh trong Bash?

Tôi cần chuyển đổi các đối số thành một mảng script bash thông thường; Tôi nhận ra rằng tôi có thể sử dụng các ngôn ngữ khác (ví dụ Python) nhưng cần phải làm điều này trong bash. Tôi đoán tôi đang tìm kiếm một chức năng "chắp thêm" hoặc một cái gì đó tương tự?

CẬP NHẬT: Tôi cũng muốn hỏi làm thế nào để kiểm tra các đối số bằng 0 và gán giá trị mảng mặc định và nhờ câu trả lời bên dưới, đã có thể làm cho điều này hoạt động:

if [ "$#" -eq 0 ]; then
  myArray=( defaultarg1 defaultarg2 )
else
  myArray=( "$@" )
fi

Câu trả lời:


206

Trên thực tế, các đối số dòng lệnh của bạn thực tế giống như một mảng. Ít nhất, bạn có thể coi $@biến giống như một mảng. Điều đó nói rằng, bạn có thể chuyển đổi nó thành một mảng thực tế như thế này:

myArray=( "$@" )

Nếu bạn chỉ muốn nhập một số đối số và đưa chúng vào $@giá trị, hãy sử dụng set:

$ set -- apple banana "kiwi fruit"
$ echo "$#"
3
$ echo "$@"
apple banana kiwi fruit

Hiểu cách sử dụng cấu trúc đối số đặc biệt hữu ích trong POSIX sh, không có gì khác giống như một mảng.


2
Cảm ơn! Hoạt động tuyệt vời! Chỉ là hỏi về cách kiểm tra các đối số bằng không và gán giá trị mảng mặc định và $ # hoạt động hoàn hảo cho điều đó!
Suman

1
setcho phép bạn đặt tham số vị trí cho phạm vi. Nó cũng cho phép bạn thiết lập các tùy chọn vỏ. Bạn có thể làm set foo, điều đó có nghĩa là $1mở rộng thành "foo", nhưng nếu các tham số của bạn bắt đầu bằng dấu gạch ngang setsẽ cho rằng bạn có nghĩa là đặt tùy chọn shell. Dấu gạch ngang kép đảm bảo rằng tất cả các tham số sau được hiểu là tham số vị trí được đặt.
kojiro

11
Một gotcha: echo $@sẽ in tất cả các đối số, nhưng echo $myArraysẽ chỉ in phần tử đầu tiên. Để xem tất cả, sử dụng echo ${myArray[@]}.
z0r

4
@ z0r Nếu bạn không đặt dấu ngoặc kép xung quanh các bản mở rộng đó thì bash sẽ viết lại từ đó và có thể mất ý nghĩa.
kojiro

Phải, cách chung để "splat" một mảng và sử dụng từng phần tử là "${myArray[@]}". Nếu bạn muốn lặp qua mảng, bạn cần dấu ngoặc kép để tránh chia tách các phần tử riêng lẻ trên IFS
BallpointBen

66

Có lẽ điều này có thể giúp:

myArray=("$@") 

ngoài ra, bạn có thể lặp lại các đối số bằng cách bỏ qua 'trong':

for arg; do
   echo "$arg"
done

sẽ tương đương

for arg in "${myArray[@]}"; do
   echo "$arg"
done

3
Câu hỏi của người mới: Làm thế nào để bash biết những gì cần đưa vào argtrường - đó có phải là một biến được xác định trước không? ${var}được mở rộng đến nội dung của var. ${var[n]}được mở rộng đến nội dung của phần tử ncủa mảng var. Có phải ${var[@]}sau đó đang mở rộng toàn bộ mảng, tức là ${var[0]} ${var[1]} ... ${var[n]}(với nchỉ mục của phần tử cuối cùng)?
Christian

4
[for] không có [in] sẽ lặp qua mảng đối số $ @ ($ 1, $ 2, v.v.). Cũng có thể được đặt bằng lệnh [set], ví dụ như set - arg1 arg2
Nahuel Fouilleul

17

Trên thực tế, danh sách các tham số có thể được truy cập cùng, $1 $2 ...v.v ...
Chính xác là tương đương với:

${!i}

Vì vậy, danh sách các tham số có thể được thay đổi theo tập hợp
${!i}là cách chính xác để truy cập chúng:

$ set -- aa bb cc dd 55 ff gg hh ii jjj kkk lll
$ for ((i=0;i<=$#;i++)); do echo "$#" "$i" "${!i}"; done
12 1 aa
12 2 bb
12 3 cc
12 4 dd
12 5 55
12 6 ff
12 7 gg
12 8 hh
12 9 ii
12 10 jjj
12 11 kkk
12 12 lll

Đối với trường hợp cụ thể của bạn, điều này có thể được sử dụng (không cần mảng), để đặt danh sách các đối số khi không có đối số nào được đưa ra:

if [ "$#" -eq 0 ]; then
    set -- defaultarg1 defaultarg2
fi

Điều này chuyển sang biểu thức thậm chí đơn giản hơn:

[ "$#" == "0" ] && set -- defaultarg1 defaultarg2

Không phải ví dụ echo là: echo "$#" "$i+1" "${!i}";để có được đầu ra chính xác như được hiển thị?
Zael

6

Đây là một cách sử dụng khác:

#!/bin/bash
array=( "$@" )
arraylength=${#array[@]}
for (( i=0; i<${arraylength}; i++ ));
do
   echo "${array[$i]}"
done

4

Dễ dàng hơn Tuy nhiên, bạn có thể hoạt động trực tiếp trên $@;)

Đây là cách để vượt qua một danh sách các đối số trực tiếp từ dấu nhắc:

function echoarg { for stuff in "$@" ; do echo $stuff ; done ; } 
    echoarg Hey Ho Lets Go
    Hey
    Ho
    Lets
    Go

1
Thậm chí dễ dàng hơn, for stuff in "$@" ; do ...giống như for stuff ; do ...:)
kkm

1

Chế độ xem cạnh nhau về cách mảng và $ @ thực tế giống nhau.

Mã số:

#!/bin/bash

echo "Dollar-1 : $1"
echo "Dollar-2 : $2"
echo "Dollar-3 : $3"
echo "Dollar-AT: $@"
echo ""

myArray=( "$@" )

echo "A Val 0: ${myArray[0]}"
echo "A Val 1: ${myArray[1]}"
echo "A Val 2: ${myArray[2]}"
echo "A All Values: ${myArray[@]}"

Đầu vào:

./bash-array-practice.sh 1 2 3 4

Đầu ra:

Dollar-1 : 1
Dollar-2 : 2
Dollar-3 : 3
Dollar-AT: 1 2 3 4

A Val 0: 1
A Val 1: 2
A Val 2: 3
A All Values: 1 2 3 4

1

Tầm quan trọng của dấu ngoặc kép đáng được nhấn mạnh. Giả sử một đối số chứa khoảng trắng.

Mã số:

#!/bin/bash
printf 'arguments:%s\n' "$@"
declare -a arrayGOOD=( "$@" )
declare -a arrayBAAD=(  $@  )

printf '\n%s:\n' arrayGOOD
declare -p arrayGOOD
arrayGOODlength=${#arrayGOOD[@]}
for (( i=1; i<${arrayGOODlength}+1; i++ ));
do
   echo "${arrayGOOD[$i-1]}"
done

printf '\n%s:\n' arrayBAAD
declare -p arrayBAAD
arrayBAADlength=${#arrayBAAD[@]}
for (( i=1; i<${arrayBAADlength}+1; i++ ));
do
   echo "${arrayBAAD[$i-1]}"
done

Đầu ra:

> ./bash-array-practice.sh 'The dog ate the "flea" -- and ' the mouse.
arguments:The dog ate the "flea" -- and 
arguments:the
arguments:mouse.

arrayGOOD:
declare -a arrayGOOD='([0]="The dog ate the \"flea\" -- and " [1]="the" [2]="mouse.")'
The dog ate the "flea" -- and 
the
mouse.

arrayBAAD:
declare -a arrayBAAD='([0]="The" [1]="dog" [2]="ate" [3]="the" [4]="\"flea\"" [5]="--" [6]="and" [7]="the" [8]="mouse.")'
The
dog
ate
the
"flea"
--
and
the
mouse.
> 
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.