แปลงอาร์กิวเมนต์บรรทัดคำสั่งเป็นอาร์เรย์ใน Bash


162

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

ฉันต้องการสิ่งนี้:

./something.sh arg1 arg2 arg3

และแปลงเป็น

myArray=( arg1 arg2 arg3 )

เพื่อให้ฉันสามารถใช้ myArray เพื่อใช้ในสคริปต์ต่อไป

โพสต์ SO ก่อนหน้านี้ใกล้เข้ามา แต่ไม่ได้เข้าไปในวิธีการสร้างอาร์เรย์: ฉันจะแยกอาร์กิวเมนต์บรรทัดคำสั่งใน Bash ได้อย่างไร

ฉันต้องการแปลงอาร์กิวเมนต์เป็นอาร์เรย์สคริปต์ทุบตีปกติ ฉันรู้ว่าฉันสามารถใช้ภาษาอื่น (Python เป็นต้น) แต่ต้องทำอย่างนี้ในการทุบตี ฉันเดาว่าฉันกำลังมองหาฟังก์ชั่น "ผนวก" หรืออะไรที่คล้ายกัน?

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

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

คำตอบ:


208

ที่จริงอาร์กิวเมนต์บรรทัดคำสั่งของคุณเป็นจริงเช่นอาร์เรย์แล้ว อย่างน้อยคุณสามารถจัดการกับ$@ตัวแปรได้เหมือนอาร์เรย์ ที่กล่าวว่าคุณสามารถแปลงเป็นอาร์เรย์จริงเช่นนี้:

myArray=( "$@" )

หากคุณต้องการพิมพ์อาร์กิวเมนต์และป้อน$@ค่าให้ใช้set:

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

การทำความเข้าใจวิธีใช้โครงสร้างอาร์กิวเมนต์มีประโยชน์อย่างยิ่งใน POSIX sh ซึ่งไม่มีอะไรเหมือนอาร์เรย์


2
ขอบคุณ! ใช้งานได้ดี! เป็นเพียงการถามวิธีตรวจสอบข้อโต้แย้งเป็นศูนย์และกำหนดค่าอาร์เรย์เริ่มต้นและ $ # ทำงานได้อย่างสมบูรณ์แบบสำหรับสิ่งนั้น!
Suman

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

12
หนึ่ง gotcha: echo $@จะพิมพ์อาร์กิวเมนต์ทั้งหมด แต่echo $myArrayจะพิมพ์องค์ประกอบแรกเท่านั้น echo ${myArray[@]}จะเห็นพวกเขาทุกการใช้งาน
z0r

4
@ z0r หากคุณไม่ใส่เครื่องหมายอัญประกาศล้อมรอบการขยายเหล่านั้นแล้ว bash จะปรับคำใหม่อีกครั้งและอาจสูญเสียความหมาย
kojiro

ขวาวิธีทั่วไปที่ "แดง" "${myArray[@]}"อาร์เรย์และใช้ของแต่ละองค์ประกอบ หากคุณต้องการวนซ้ำแถวลำดับคุณจำเป็นต้องมีเครื่องหมายอัญประกาศเพื่อหลีกเลี่ยงการแยกองค์ประกอบแต่ละตัวใน IFS
BallpointBen

66

บางทีนี่อาจช่วยได้:

myArray=("$@") 

นอกจากนี้คุณสามารถทำซ้ำมากกว่าอาร์กิวเมนต์โดยละเว้น 'ใน':

for arg; do
   echo "$arg"
done

จะเทียบเท่า

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

3
คำถาม Newbie: ทุบตีรู้ได้อย่างไรว่าจะใส่อะไรลงในargฟิลด์ - มันเป็นตัวแปรที่กำหนดไว้ล่วงหน้า? มีการขยายไปยังเนื้อหาของ${var} มีการขยายไปยังเนื้อหาขององค์ประกอบของอาร์เรย์ ถูกแล้วขยายอาร์เรย์ทั้งหมดคือ(กับการเป็นดัชนีองค์ประกอบสุดท้ายของ)? var${var[n]}nvar${var[@]}${var[0]} ${var[1]} ... ${var[n]}n
คริสเตียน

4
[สำหรับ] โดยไม่มี [ใน] จะวนซ้ำอาร์กิวเมนต์อาร์เรย์ $ @ ($ 1, $ 2, ฯลฯ ) ซึ่งสามารถตั้งค่าได้ด้วยคำสั่ง [set] เช่น set - arg1 arg2
Nahuel Fouilleul

17

ที่จริงแล้วรายการพารามิเตอร์สามารถเข้าถึงได้ด้วย$1 $2 ...เป็นต้น
ซึ่งเทียบเท่ากับ:

${!i}

ดังนั้นรายการของพารามิเตอร์สามารถเปลี่ยนแปลงได้ด้วยชุด
และ${!i}เป็นวิธีที่ถูกต้องในการเข้าถึงพวกเขา:

$ 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

สำหรับกรณีเฉพาะของคุณสามารถใช้สิ่งนี้ (โดยไม่จำเป็นต้องใช้อาร์เรย์) เพื่อตั้งค่ารายการอาร์กิวเมนต์เมื่อไม่มีการกำหนด:

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

ซึ่งแปลเป็นนิพจน์ที่ง่ายกว่านี้:

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

ตัวอย่าง echo ไม่ควรเป็น: echo "$#" "$i+1" "${!i}";เพื่อให้ได้ผลลัพธ์ตามที่แสดง?
Zael

6

นี่คือการใช้งานอื่น:

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

4

ง่ายกว่าคุณสามารถใช้งานได้โดยตรงบน$@;)

ต่อไปนี้เป็นวิธีทำรายการ aa ของ args โดยตรงจากพร้อมต์:

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

1
ง่ายยิ่งขึ้นfor stuff in "$@" ; do ...ก็เหมือนกับfor stuff ; do ...:)
kkm

1

มุมมองแบบเคียงข้างกันว่าอาร์เรย์และ $ @ เหมือนกันอย่างไร

รหัส:

#!/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[@]}"

การป้อนข้อมูล:

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

เอาท์พุท:

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

ความสำคัญของเครื่องหมายคำพูดคู่คือการเน้นที่คุ้มค่า สมมติว่าอาร์กิวเมนต์มีช่องว่าง

รหัส:

#!/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

เอาท์พุท:

> ./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.
> 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.