Linux bash: การกำหนดตัวแปรหลายตัว


121

มีอยู่ใน linux bash ซึ่งคล้ายกับโค้ดต่อไปนี้ใน PHP:

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

กล่าวคือคุณกำหนดค่าที่สอดคล้องกันให้กับตัวแปร 3 ตัวในประโยคเดียว

สมมติว่าฉันมีฟังก์ชัน bash myBashFuntionที่เขียนเพื่อ stdout สตริง "qwert asdfg zxcvb" เป็นไปได้ไหมที่จะทำสิ่งต่างๆเช่น:

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

ส่วนที่อยู่ทางซ้ายของเครื่องหมายเท่ากับไม่ใช่ไวยากรณ์ที่ถูกต้องแน่นอน ฉันแค่พยายามอธิบายสิ่งที่ฉันขอ

สิ่งที่ได้ผลมีดังต่อไปนี้:

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

แต่อาร์เรย์ที่จัดทำดัชนีจะไม่สามารถอธิบายได้เหมือนกับชื่อตัวแปรธรรมดา
อย่างไรก็ตามฉันสามารถทำได้:

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

แต่นี่เป็นอีก 3 ข้อความที่ฉันต้องการหลีกเลี่ยง

ฉันกำลังมองหาไวยากรณ์ทางลัด เป็นไปได้ไหม?

คำตอบ:


222

สิ่งแรกที่อยู่ในใจของฉัน:

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

ผลลัพธ์คือไม่น่าแปลกใจ

1|2|3

4
จะมีการทำให้สิ่งนี้ทำงานได้หรือไม่หากตัวแปรแรกมีช่องว่าง
Rucent88

8
@ ไมเคิลใช้read -d "\n" v1 v2 <<<$(cmd)งานได้อย่างสมบูรณ์แบบ ขอบคุณ!
Rucent88

1
@LeeNetherton จุดดีแม้ว่าฉันไม่แน่ใจว่ามีใครต้องการสถานะการส่งคืนของคำสั่ง echo :-) ฉันคิดว่าในขณะที่เขียนคำตอบ bash ที่สนับสนุนไวยากรณ์นี้ไม่ค่อยพบบ่อย (ตามที่ติดตั้งโดยค่าเริ่มต้น) แม้ว่าฉัน ไม่แน่ใจ 100%
Michael Krelin - แฮ็กเกอร์

4
@ MichaelKrelin- แฮ็กเกอร์แน่นอนว่าสถานะการส่งคืนechoนั้นไม่มีจุดหมาย แต่ฉันใช้เทคนิคนี้เพื่อคืนค่าหลายค่าจากสคริปต์ที่ฉันสนใจเกี่ยวกับสถานะการส่งคืน ฉันคิดว่าฉันจะแบ่งปันสิ่งที่ฉันค้นพบ
Lee Netherton

1
เพื่อความปลอดภัยคุณควรใช้read -r:do not allow backslashes to escape any characters
Tom Hale

18

ฉันต้องการกำหนดค่าให้กับอาร์เรย์ ดังนั้นฉันจึงขยายแนวทางของ Michael Krelin :

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

ซึ่งให้ผลตอบแทน:

2|4|6 

อย่างที่คาดไว้.


2
ในการใส่ค่าในอาร์เรย์มีวิธีง่ายๆอยู่แล้วซึ่งฉันได้กล่าวถึงในคำถาม:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}
GetFree

ใช่ฉันมองข้ามสิ่งนั้นไปแล้ว แม้ว่าฉันจะโต้แย้งว่าข้อเสนอแนะของฉันเหมาะกับการกำหนดอาร์เรย์ที่ใหญ่กว่า
soundray

@soundray การแก้ปัญหาของคุณใช้การขยายตัวและต่อไปนี้ทุบตีเป็นสิ่งที่ฉันสงสัยว่ามันจะทำงานได้ดีในสถานการณ์นั้น (แต่ฉันไม่ได้ตรวจสอบ)
Camilo Martin

เพื่อความปลอดภัยคุณควรใช้read -r:do not allow backslashes to escape any characters
Tom Hale

5

ฉันคิดว่านี่อาจช่วยได้ ...

ในการแยกวันที่ป้อนข้อมูลของผู้ใช้ (mm / dd / yyyy) ในสคริปต์ของฉันฉันเก็บวันเดือนและปีไว้ในอาร์เรย์แล้วใส่ค่าลงในตัวแปรแยกกันดังนี้:

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

ทำไมไม่หลีกเลี่ยง 4 subshells บวกกับกระบวนการ sed พิเศษและทำทุกอย่างในบรรทัดเดียว:IFS=/ read -r m d y < <(echo 12/29/2009)
Amit Naidu

5

บางครั้งคุณต้องทำอะไรที่ขี้ขลาด สมมติว่าคุณต้องการอ่านจากคำสั่ง (ตัวอย่างวันที่โดย SDGuero เป็นต้น) แต่คุณต้องการหลีกเลี่ยงหลายส้อม

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

คุณสามารถไปป์ในคำสั่ง read ได้ แต่คุณต้องใช้ตัวแปรภายใน subshell:

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

ผลลัพธ์ใน ...

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

readคำสั่งไม่ได้เกิดขึ้นใน subshell เพราะการจัดฟันก็เพราะคุณได้มีคำสั่งอ่านบนด้านขวาของท่อ คุณต้องรันreadคำสั่งในเชลล์ปัจจุบันซึ่งคุณสามารถทำได้เช่นread day month year <<< `date "+%d %m %Y"`
pneumatics

ไม่ - สิ่งที่read เกิดขึ้นแต่ขอบเขตของตัวแปรที่อ่านว่าตกอยู่นอกขอบเขตเมื่อส่วนย่อยของไปป์ไลน์สิ้นสุดลง
Otheus

1
ความคิดเห็นของฉันเป็นเรื่องเกี่ยวกับเหตุผลที่ว่าทำไมการอ่านเกิดขึ้นใน subshell และฉันตระหนักถึงตอนนี้ผมอ่านผิดสิ่งที่คุณเขียน ฉันคิดว่าคุณหมายความว่า subshell ถูกสร้างขึ้นเพราะคุณใช้วงเล็บปีกการอบ ๆ คำสั่งประกอบ แต่! เหตุผลที่คุณยกตัวอย่างนั้นคือเพื่อหลีกเลี่ยงการฟอร์ก แต่จะไม่ใช้ส้อมย่อยด้วยหรือไม่?
pneumatics

ตัวอย่างแรกต้องการส้อมเพียงตัวเดียว: เพื่อให้ bash สามารถเปิดคำสั่ง date ได้ ในตัวอย่างที่สองคุณตั้งค่าไปป์ไลน์ระหว่างวันที่และเชลล์ย่อยของคุณ ฉันคิดว่าการทุบตีในวันนี้ฉลาดพอที่จะไม่แยกเข้าไปใน subshell แต่ฉันไม่แน่ใจเกี่ยวกับเรื่องนั้น ในอัตราใด ๆ มันมีลักษณะเหมือนมันจะ :)
Otheus

0

บทที่ 5 ของBash Cookbookโดย O'Reilly กล่าวถึง (ตามความยาว) ถึงเหตุผลของข้อกำหนดในการกำหนดตัวแปรว่าไม่มีช่องว่างรอบ ๆ เครื่องหมาย '='

MYVAR="something"

คำอธิบายเกี่ยวข้องกับการแยกแยะระหว่างชื่อของคำสั่งและตัวแปร (โดยที่ '=' อาจเป็นอาร์กิวเมนต์ที่ถูกต้อง)

ทั้งหมดนี้ดูเหมือนจะเป็นเหตุผลเล็กน้อยหลังจากเหตุการณ์ แต่ไม่ว่าในกรณีใด ๆ จะไม่มีการกล่าวถึงวิธีการกำหนดให้กับรายการตัวแปร


ใช่ฉันรู้. ฉันเพิ่งเพิ่มช่องว่างตรงนี้และตรงนั้นเพื่อประโยชน์ในการอ่าน
ฟรี

นั่นเป็นแรงจูงใจที่ไม่ดี: จะเกิดอะไรขึ้นถ้า ' ;' เป็นอาร์กิวเมนต์ที่ถูกต้อง? เมื่อฉันเขียนls ; cdมันยังคงโทรlsและcdแม้จะมีช่องว่าง หากฉันต้องการแสดงรายการไดเรกทอรีที่เรียก;และcdฉันสามารถพิมพ์ls ';' cdได้
PieterNuyts
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.