Linux bash: Chuyển nhượng nhiều biến


121

Có tồn tại trong bash linux một cái gì đó tương tự như mã sau trong PHP:

list($var1, $var2, $var3) = function_that_returns_a_three_element_array() ;

tức là bạn gán trong một câu một giá trị tương ứng cho 3 biến khác nhau.

Giả sử tôi có hàm bash myBashFuntionghi để tạo chuỗi "qwert asdfg zxcvb". Có thể làm điều gì đó như:

(var1 var2 var3) = ( `myBashFuntion param1 param2` )

Tất nhiên, phần ở bên trái của dấu bằng không phải là cú pháp hợp lệ. Tôi chỉ đang cố gắng giải thích những gì tôi đang yêu cầu.

Tuy nhiên, những gì hoạt động là như sau:

array = ( `myBashFuntion param1 param2` )
echo ${array[0]} ${array[1]} ${array[2]}

Nhưng một mảng được lập chỉ mục không mang tính mô tả như các tên biến đơn giản.
Tuy nhiên, tôi chỉ có thể làm:

var1 = ${array[0]} ; var2 = ${array[1]} ; var3 = ${array[2]}

Nhưng đó là 3 câu nói nữa mà tôi muốn tránh.

Tôi chỉ đang tìm kiếm một cú pháp tắt. Có khả thi không?

Câu trả lời:


222

Điều đầu tiên xuất hiện trong đầu tôi:

read -r a b c <<<$(echo 1 2 3) ; echo "$a|$b|$c"

đầu ra, không có gì đáng ngạc nhiên

1|2|3

4
Có cách nào để làm cho điều này hoạt động nếu biến đầu tiên chứa một khoảng trắng không?
Rucent88 Ngày

7
@Michael Sử dụng read -d "\n" v1 v2 <<<$(cmd)hoạt động hoàn hảo. Cảm ơn bạn!
Rucent88 Ngày

1
@LeeNetherton, điểm tốt, mặc dù tôi không chắc liệu một người có cần trạng thái trả về của lệnh echo hay không :-) Tôi nghĩ tại thời điểm viết câu trả lời bash hỗ trợ cú pháp này ít phổ biến hơn (như được cài đặt theo mặc định), mặc dù tôi Tôi không chắc chắn 100%.
Michael Krelin - hacker

4
@ MichaelKrelin-hacker chắc chắn, trạng thái trả về echolà vô nghĩa, nhưng tôi đã sử dụng kỹ thuật này để trả về nhiều giá trị từ một tập lệnh mà tôi đã quan tâm đến trạng thái trả về. Tôi nghĩ rằng tôi sẽ chia sẻ những phát hiện của tôi.
Lee Netherton

1
Để an toàn bạn nên sử dụng: read -r:do not allow backslashes to escape any characters
Tom Hale

18

Tôi muốn gán các giá trị cho một mảng. Vì vậy, mở rộng cách tiếp cận của Michael Krelin , tôi đã làm:

read a[{1..3}] <<< $(echo 2 4 6); echo "${a[1]}|${a[2]}|${a[3]}"

mang lại:

2|4|6 

như mong đợi.


2
Để đặt các giá trị trong một mảng, đã có một giải pháp đơn giản mà tôi đã đề cập trong câu hỏi:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}
GetFree

Vâng, tôi đã bỏ qua điều đó. Tuy nhiên, tôi sẽ tranh luận rằng gợi ý của tôi phù hợp hơn để gán các mảng lớn hơn.
soundray

@soundray Giải pháp của bạn sử dụng mở rộng và chuỗi đây, tôi nghi ngờ nó sẽ hoạt động tốt trong trường hợp đó (nhưng tôi đã không kiểm tra).
Camilo Martin

Để an toàn bạn nên sử dụng: read -r:do not allow backslashes to escape any characters
Tom Hale

5

Tôi nghĩ điều này có thể giúp ...

Để chia nhỏ ngày do người dùng nhập (mm / dd / yyyy) trong tập lệnh của tôi, tôi lưu trữ ngày, tháng và năm vào một mảng, sau đó đặt các giá trị vào các biến riêng biệt như sau:

DATE_ARRAY=(`echo $2 | sed -e 's/\// /g'`)
MONTH=(`echo ${DATE_ARRAY[0]}`)
DAY=(`echo ${DATE_ARRAY[1]}`)
YEAR=(`echo ${DATE_ARRAY[2]}`)

Tại sao không tránh 4 subhells cộng với một quy trình sed bổ sung và chỉ làm tất cả những điều đó trong một dòng:IFS=/ read -r m d y < <(echo 12/29/2009)
Amit Naidu

5

Đôi khi bạn phải làm điều gì đó sôi nổi. Giả sử bạn muốn đọc một lệnh (ví dụ ngày tháng của SDGuero chẳng hạn) nhưng bạn muốn tránh nhiều nhánh.

read month day year << DATE_COMMAND
 $(date "+%m %d %Y")
DATE_COMMAND
echo $month $day $year

Bạn cũng có thể đưa vào lệnh read, nhưng sau đó bạn phải sử dụng các biến trong một vỏ con:

day=n/a; month=n/a; year=n/a
date "+%d %m %Y" | { read day month year ; echo $day $month $year; }
echo $day $month $year

kết quả trong...

13 08 2013
n/a n/a n/a

Các readlệnh không xảy ra trong một subshell vì niềng răng, đó là vì bạn đã có lệnh đọc ở phía bên phải của đường ống. Bạn cần phải chạy readlệnh trong shell hiện hành, mà bạn có thể làm nhưread day month year <<< `date "+%d %m %Y"`
khí nén

Không - điều này read xảy ra nhưng phạm vi của các biến mà nó đọc vào nằm ngoài phạm vi khi vỏ con của đường ống kết thúc.
Otheus,

1
Nhận xét của tôi là về lý do tại sao việc đọc xảy ra trong một đoạn ngắn, và tôi nhận ra bây giờ tôi đã đọc sai những gì bạn viết. Tôi nghĩ rằng bạn muốn nói rằng vỏ con được tạo bởi vì bạn đã sử dụng dấu ngoặc nhọn xung quanh câu lệnh ghép. Nhưng! Lý do bạn đưa ra ví dụ đó là để tránh fork, và cũng không phải là subshell fork?
khí nén

Ví dụ đầu tiên yêu cầu chính xác một fork: để bash có thể khởi chạy lệnh date. Trong ví dụ thứ hai, bạn thiết lập một đường dẫn giữa ngày và lớp phụ của bạn. Tôi nghĩ rằng bash những ngày này đủ thông minh để không thực sự chuyển sang vỏ con, nhưng tôi không chắc về điều đó. Ở bất kỳ mức độ nào, có vẻ như nó sẽ :)
Otheus

0

Chương 5 của Sách dạy nấu ăn Bash của O'Reilly, thảo luận (ở một số độ dài) lý do yêu cầu trong một phép gán biến không có khoảng trắng xung quanh dấu '='

MYVAR="something"

Lời giải thích có liên quan đến việc phân biệt giữa tên của lệnh và biến (trong đó '=' có thể là một đối số hợp lệ).

Tất cả điều này dường như hơi giống như biện minh sau sự kiện, nhưng trong mọi trường hợp, không có đề cập đến phương pháp gán cho danh sách các biến.


Vâng tôi biết. Tôi chỉ thêm khoảng trống ở đây và ở đó để dễ đọc
GetFree

Quả thực đó là một động cơ kém: Điều gì sẽ xảy ra nếu ' ;' là một đối số hợp lệ? Khi tôi viết ls ; cdnó vẫn gọi lscdmặc dù có khoảng trắng. Nếu tôi muốn liệt kê các thư mục được gọi ;cdtôi có thể nhập ls ';' cd.
PieterNuyts
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.