จะเข้าถึงอาร์กิวเมนต์บรรทัดคำสั่งของผู้โทรภายในฟังก์ชันได้อย่างไร


102

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

# Demo function
function stuff {
  echo $0 $*
}

# Echo's the name of the script, but no command line arguments
stuff

# Echo's everything I want, but trying to avoid
stuff $*

3
ฉันรู้สึกสับสนคุณต้องการให้ args โดยไม่ผ่านพวกเขา?
Ravi Vyas

4
ใช่ประเด็นคือการได้รับอาร์กิวเมนต์บรรทัดคำสั่งจากภายในฟังก์ชันมากเกินไปโดยไม่ส่งผ่านเป็นอาร์กิวเมนต์เชิงฟังก์ชัน มันเกี่ยวข้องกับสถานการณ์การจัดการข้อผิดพลาดที่ฉันต้องการจัดการข้อผิดพลาดตามอาร์กิวเมนต์บรรทัดคำสั่งโดยไม่ขึ้นอยู่กับอาร์กิวเมนต์ที่ส่งเข้ามาในฟังก์ชัน
DonGar

FYI $*เป็นรถที่มีปัญหามาก - จะเปลี่ยน./yourScript "first argument" "second argument"เป็น./yourscript "first" "argument" "second" "argument"หรือเปลี่ยน./yourscript '*.txt'เป็นสิ่งที่ชอบ./yourscript one.txt two.txtแม้จะมีเครื่องหมายคำพูด
Charles Duffy

คำตอบ:


48

การอ่านคู่มืออ้างอิง bash ของฉันบอกว่าสิ่งนี้ถูกบันทึกใน BASH_ARGV แม้ว่าจะพูดถึง "สแต็ก" มากก็ตาม

#!/bin/bash

function argv {
    for a in ${BASH_ARGV[*]} ; do
      echo -n "$a "
    done
    echo
}

function f {
    echo f $1 $2 $3
    echo -n f ; argv
}

function g {
    echo g $1 $2 $3
    echo -n g; argv
    f
}

f boo bar baz
g goo gar gaz

บันทึกใน f.sh

$ ./f.sh arg0 arg1 arg2
f boo bar baz
farg2 arg1 arg0 
g goo gar gaz
garg2 arg1 arg0 
f
farg2 arg1 arg0 

5
โปรดทราบว่าการแปลงอาร์เรย์แบบนั้นจะทำให้ args อยู่ในลำดับย้อนกลับจากบรรทัดคำสั่ง
Andrew Backer

97

หากคุณต้องการมีอาร์กิวเมนต์ C สไตล์ (อาร์เรย์อาร์กิวเมนต์ + จำนวนอาร์กิวเมนต์) คุณสามารถใช้$@และ$#.

$#ให้จำนวนอาร์กิวเมนต์
$@ให้ข้อโต้แย้งทั้งหมดแก่คุณ args=("$@")คุณสามารถเปิดนี้เป็นอาร์เรย์โดย

ตัวอย่างเช่น:

args=("$@")
echo $# arguments passed
echo ${args[0]} ${args[1]} ${args[2]}

โปรดทราบว่านี่${args[0]}คืออาร์กิวเมนต์แรกไม่ใช่ชื่อสคริปต์ของคุณ


5
สิ่งนี้ไม่ได้ตอบคำถาม แต่เป็นการถามเกี่ยวกับการส่งอาร์กิวเมนต์บรรทัดคำสั่งไปยังฟังก์ชันเชลล์
Cascabel

6
@Jefromi จริงๆแล้วมันตอบคำถามได้อย่างดีเยี่ยม คุณสามารถใช้argsอาร์เรย์จากภายในฟังก์ชันได้หากคุณเริ่มต้นก่อนตามที่อธิบายไว้
vadipp

1
ฉันพบว่าสิ่งนี้สะอาดกว่าการทำซ้ำบน args
Félix Gagnon-Grenier

1
นี่เป็นเรื่องง่ายและสะดวก คำตอบที่ดี คุณโพสต์สิ่งนี้เมื่อ 7 ปีที่แล้วสวัสดีจากอนาคต: กรกฎาคม 2017
SDsolar

ยิ่งไปกว่านั้นคือการอ้างถึงเช่นecho "${args[0]} ${args[1]} ${args[2]}"หรืออาร์กิวเมนต์อาจมีการขยายชื่อไฟล์
Benjamin W.

18
#!/usr/bin/env bash

echo name of script is $0
echo first argument is $1
echo second argument is $2
echo seventeenth argument is $17
echo number of arguments is $#

แก้ไข: โปรดดูความคิดเห็นของฉันเกี่ยวกับคำถาม


17

ความคิดเห็นของ Ravi คือคำตอบเป็นหลัก ฟังก์ชันใช้ข้อโต้แย้งของตนเอง ถ้าคุณต้องการให้เหมือนกับอาร์กิวเมนต์บรรทัดคำสั่งคุณต้องส่งผ่านเข้าไปมิฉะนั้นคุณจะเรียกใช้ฟังก์ชันโดยไม่มีอาร์กิวเมนต์อย่างชัดเจน

ที่กล่าวว่าคุณสามารถทำได้ถ้าคุณต้องการจัดเก็บอาร์กิวเมนต์บรรทัดคำสั่งในอาร์เรย์ส่วนกลางเพื่อใช้ภายในฟังก์ชันอื่น ๆ :

my_function() {
    echo "stored arguments:"
    for arg in "${commandline_args[@]}"; do
        echo "    $arg"
    done
}

commandline_args=("$@")

my_function

คุณมีการเข้าถึงอาร์กิวเมนต์บรรทัดคำสั่งผ่านcommandline_argsตัวแปรไม่ได้$@, $1, $2ฯลฯ แต่พวกเขากำลังที่มีอยู่ ฉันไม่รู้วิธีกำหนดโดยตรงให้กับอาร์เรย์อาร์กิวเมนต์ แต่ถ้ามีใครรู้โปรดแจ้งให้ฉันเข้าใจ!

นอกจากนี้โปรดสังเกตวิธีที่ฉันใช้และยกมา$@- นี่คือวิธีที่คุณมั่นใจได้ว่าอักขระพิเศษ (ช่องว่าง) จะไม่เลอะเทอะ



2

หนึ่งสามารถทำเช่นนี้เช่นกัน

#!/bin/bash
# script_name function_test.sh
function argument(){
for i in $@;do
    echo $i
done;
}
argument $@

ตอนนี้เรียกสคริปต์ของคุณเช่น

./function_test.sh argument1 argument2

function print() {คือการรวมกันระหว่างรูปแบบการประกาศฟังก์ชันที่แตกต่างกันสองแบบ - function print {ซึ่งเป็นไวยากรณ์ ksh แบบดั้งเดิมที่ bash สนับสนุนสำหรับความเข้ากันได้แบบย้อนกลับกับ pre-POSIX (ซึ่งกล่าวคือก่อนปี 1991) ksh และprint() {ซึ่งเป็นมาตรฐาน POSIX พิจารณาใช้อย่างใดอย่างหนึ่งเพื่อให้เข้ากันได้กับเชลล์อื่น ๆ ดูwiki.bash-hackers.org/scripting/obsolete
Charles Duffy

1

คุณสามารถใช้คีย์เวิร์ด shift (ตัวดำเนินการ?) เพื่อวนซ้ำผ่านคำหลักเหล่านี้ ตัวอย่าง:

#!/bin/bash
function print()
{
    while [ $# -gt 0 ]
    do
        echo $1;
        shift 1;
    done
}
print $*;

2
function print() {คือการรวมกันระหว่างรูปแบบการประกาศฟังก์ชันที่แตกต่างกันสองแบบ - function print {ซึ่งเป็นไวยากรณ์ ksh แบบดั้งเดิมที่ bash สนับสนุนสำหรับความเข้ากันได้แบบย้อนกลับกับ pre-POSIX (ซึ่งกล่าวคือก่อนปี 1991) ksh และprint() {ซึ่งเป็นมาตรฐาน POSIX พิจารณาใช้อย่างใดอย่างหนึ่งเพื่อให้เข้ากันได้กับเชลล์อื่น ๆ ดูwiki.bash-hackers.org/scripting/obsolete
Charles Duffy

1

วิธีแก้ปัญหาของฉัน:

สร้างสคริปต์ฟังก์ชันที่เรียกเร็วกว่าฟังก์ชันอื่น ๆ ทั้งหมดโดยไม่ส่งผ่านอาร์กิวเมนต์ใด ๆ เช่นนี้:

! / bin / bash

ฟังก์ชัน init () {ORIGOPT = "- $ @ -"}

คุณสามารถเรียก init และใช้ ORIGOPT var ได้ตามต้องการนอกจากนี้ฉันมักจะกำหนด var ใหม่และคัดลอกเนื้อหาของ ORIGOPT ในฟังก์ชั่นใหม่ของฉันด้วยวิธีนี้คุณจะมั่นใจได้ว่าไม่มีใครแตะต้องมันหรือ เปลี่ยนมัน

ฉันเพิ่มช่องว่างและขีดกลางเพื่อให้ง่ายต่อการแยกวิเคราะห์ด้วย 'sed -E' และ bash จะไม่ส่งผ่านเป็นข้อมูลอ้างอิงและทำให้ ORIGOPT เติบโตขึ้นเมื่อฟังก์ชันถูกเรียกด้วยอาร์กิวเมนต์มากขึ้น

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