แปลงอาร์เรย์เป็นอาร์กิวเมนต์ของคำสั่งหรือไม่?


39

ฉันมีอาร์เรย์ของ "ตัวเลือก" ของคำสั่ง

my_array=(option1 option2 option3)

ฉันต้องการเรียกคำสั่งนี้ในสคริปต์ทุบตีโดยใช้ค่าจากอาร์เรย์เป็นตัวเลือก ดังนั้นcommand $(some magic here with my_array) "$1"กลายเป็น:

command -option1 -option2 -option3 "$1"

ฉันจะทำมันได้อย่างไร เป็นไปได้ไหม?


1
ดังนั้นคุณต้องการเพิ่ม-ไปยังจุดเริ่มต้นของแต่ละคำในmy_arrayหรือไม่
เควิน

@Kevin: ใช่และดำเนินการ ทุกบรรทัดอยู่ในสคริปต์ทุบตีเดียวกัน ฉันถามสิ่งนี้เพราะตัวเลือกเดียวกันเหล่านี้จะถูกใช้ในหลาย ๆ ที่ภายในสคริปต์ดังนั้นแทนที่จะคัดลอกพวกมันทั้งหมดไปรอบ ๆ ฉันจึงคิดถึงอาร์เรย์
บางคนยังคงใช้ MS-DOS

1
มันอาจดูไร้สาระ แต่ถ้าคุณสร้างสคริปต์เชลล์ขนาดใหญ่บางทีคุณควรดูเพิร์ลสิ่งนี้เป็นเรื่องง่ายมากที่จะทำที่นั่น
alfa64

คำตอบ:


43

ฉันต้องการbashวิธีธรรมดา:

command "${my_array[@]/#/-}" "$1"

เหตุผลหนึ่งสำหรับเรื่องนี้คือช่องว่าง ตัวอย่างเช่นถ้าคุณมี:

my_array=(option1 'option2 with space' option3)

sedโซลูชั่นที่จะเปลี่ยนมันใน-option1 -option2 -with -space -option3(ความยาว 5) แต่เหนือbashขยายตัวจะเปลี่ยนมันเป็น-option1 -option2 with space -option3(ความยาวยังคง 3) ไม่บ่อยนัก แต่บางครั้งสิ่งนี้มีความสำคัญเช่น:

bash-4.2$ my_array=('Ffoo bar' 'vOFS=fiz baz')
bash-4.2$ echo 'one foo bar two foo bar three foo bar four' | awk "${my_array[@]/#/-}" '{print$2,$3}'
 two fiz baz three

ถ้าฉันเข้าใจถูกต้องการแทนที่ตัวแปรนี้จะไม่สามารถห่อเป็นฟังก์ชันหรือไม่ได้กำหนดให้กับตัวแปรใช่ไหม มันต้องตรงไปที่การร้องขอคำสั่ง
Konrad Rudolph

1
@KonradRudolph คุณสามารถกำหนดให้กับตัวแปรอื่น ๆ ตราบใดที่คุณทำมันเป็นกำหนดอาร์เรย์: somevar=("${my_array[@]/#/-}")(หมายเหตุวงเล็บรอบค่า.) echo "${somevar[@]}"แล้วแน่นอนคุณจะต้องเก็บจัดการกับมันเป็นแถวเมื่อใช้มัน: เกี่ยวกับฟังก์ชั่นนั้นคุณถูก จำกัด ด้วยความเป็นไปได้ของภาษา คุณสามารถส่งผ่านอาร์เรย์: somefunc "${my_array[@]/#/-}"แล้วภายในคุณจะมีมันอยู่ใน:$@ function somefunc() { echo "$@"; }แต่$@จะมีพารามิเตอร์อื่นเช่นกันหากมีอยู่และไม่มีวิธีอื่นในการส่งคืนอาเรย์ที่ถูกปรับเปลี่ยนมากกว่า stdout
จัดการ

แปลกพอไม่ทำงานกับ zsh ครั้งแรกที่ฉันสะดุดสิ่งที่ทำงานในทุบตี แต่ไม่ใช่ zsh
สวัสดีแองเจิล

@ Hi-Angel คุณแน่ใจหรือว่าคุณใช้@เป็นตัวห้อยอาร์เรย์? ฉันได้ทำการทดสอบด้วย zsh 5.5.1 และความแตกต่างเพียงอย่างเดียวฉันสังเกตเห็นว่า zsh นำหน้าแต่ละรายการเมื่อเขียนเป็น${my_array[@]/#/-}อย่างไรในขณะที่ bash ทำเพื่อ*ห้อยด้วยเช่นกัน
จัดการ

โอ้ขอโทษฉันอาจทำอะไรบางอย่างผิดพลาดได้ผลจริงสำหรับฉัน!
สวัสดีแองเจิล

2

ฉันไม่ได้ประมวลผลว่ามันอยู่ในอาร์เรย์และกำลังคิดว่าคั่นด้วยช่องว่างในสตริง โซลูชันนี้จะทำงานร่วมกับสิ่งนั้น แต่เนื่องจากว่าเป็นอาร์เรย์ให้ใช้โซลูชันของ manatwork ( @{my_array[@]/#/-})


สิ่งนี้ไม่ได้เลวร้ายกับsedและ subshell regex นั้นง่ายเพียงใดขึ้นอยู่กับสิ่งที่คุณสามารถรับประกันได้เกี่ยวกับตัวเลือก หากตัวเลือกทั้งหมดเป็น "คำ" ( a-zA-Z0-9เท่านั้น) ขอบเขตคำศัพท์เริ่มต้นง่ายๆ ( \<) จะพอเพียง:

command $(echo $my_array | sed 's/\</-/g') "$1"

หากตัวเลือกของคุณมีอักขระอื่น ๆ (น่าจะเป็นไปได้มากที่สุด-) คุณจะต้องมีอะไรที่ซับซ้อนกว่านี้เล็กน้อย:

command $(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g') "$1"

^ตรงกับจุดเริ่มต้นของบรรทัด[ \t]ตรงกับช่องว่างหรือแท็บ\|ตรงกับด้านใดด้านหนึ่ง ( ^หรือ[ \t]) \( \)กลุ่ม (สำหรับ\|) และเก็บผลลัพธ์\<ตรงกับจุดเริ่มต้นของคำ \1เริ่มต้นการแทนที่โดยรักษานัดแรกจาก parens ( \(\)) และ-แน่นอนเพิ่มเส้นประที่เราต้องการ

สิ่งเหล่านี้ใช้ได้กับ gnu sed หากพวกเขาไม่ทำงานกับคุณโปรดแจ้งให้เราทราบ

และหากคุณใช้สิ่งเดียวกันหลาย ๆ ครั้งคุณอาจต้องการคำนวณเพียงครั้งเดียวและเก็บไว้:

opts="$(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g')"
...
command $opts "$1"
command $opts "$2"

สิ่งนี้ใช้ไม่ได้กับ Mac OS X sed ดังนั้นฉันต้องใช้gsed(ฉันติดตั้งโดยใช้homebrew) อีกสิ่งหนึ่ง: แทนecho $my_arrayฉันต้องทำecho ${my_array[@]}เพื่อให้ได้ไอเท็มทั้งหมดจากmy_array: echo $my_arrayให้องค์ประกอบแรกกับฉันเท่านั้น แต่ขอขอบคุณสำหรับคำตอบและคำอธิบายของ regex โดยเฉพาะเกี่ยวกับ "ขอบเขตของคำศัพท์" นี้มีประโยชน์อย่างยิ่ง :)
บางคนยังคงใช้ MS-DOS

ฉันต้องการออกจากสคริปต์หากระบบของระบบไม่สามารถใช้งานร่วมกับคุณสมบัติขอบเขตคำนี้ได้ ฉันจะทำอย่างไร กำลังพิมพ์รุ่น sed และทำการเปรียบเทียบ เพิ่มคุณลักษณะนี้ในเวอร์ชันใด
ใครบางคนยังคงใช้ MS-DOS

1
@ SomebodystillusesyouMS-DOS ฉันคิดแรกคือการตรวจสอบโดยตรงไม่ว่าจะทำงาน [ $(echo x | sed 's/\</y/') == "yx" ] || exit-
Kevin

2
สิ่งนี้จะแตกถ้าองค์ประกอบอาเรย์ใด ๆ มีอักขระพิเศษโดยเฉพาะอย่างยิ่งที่ว่างเปล่าและช่องว่างที่ชัดเจน
Gilles 'หยุดความชั่วร้าย'

1
@ somebodystilluses คุณ -MS-Gilles ถูกต้องคุณควรเปลี่ยนการยอมรับของคุณเป็น manatwork
Kevin

0
[srikanth@myhost ~]$ sh sample.sh 

-option1 -option2 -option3

[srikanth@myhost ~]$ cat sample.sh

#!/bin/bash

my_array=(option1 option2 option3)

echo ${my_array[@]} | sed 's/\</-/g'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.