รับอาร์กิวเมนต์ล่าสุดที่ส่งผ่านไปยังเชลล์สคริปต์


272

$1เป็นอาร์กิวเมนต์แรก
$@คือทั้งหมดของพวกเขา

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


ฉันใช้ทุบตี แต่โซลูชันที่พกพาได้ดีกว่าดีกว่า
โทมัส


10
ใช้ยังสามารถใช้ $ {! #}
Prateek Joshi

11
เพียงทุบตีที่คำตอบเควินเล็ก ๆ น้อย ๆ${!#}เสนอที่เรียบง่าย bash -c 'echo ${!#}' arg1 arg2 arg3ทดสอบได้โดยใช้ สำหรับทุบตี , kshและzshที่คำตอบที่เดนนิสวิลเลียมสัน${@: -1}เสนอ นอกจากนี้${*: -1}ยังสามารถใช้ zsh -c 'echo ${*: -1}' arg1 arg2 arg3ทดสอบได้โดยใช้ แต่นั่นไม่ได้ทำงานให้กับประ , cshและtcsh
olibre

2
${!#}ไม่เหมือน${@: -1}กันยังใช้งานได้กับการขยายพารามิเตอร์ bash -c 'echo ${!#%.*}' arg1.out arg2.out arg3.outคุณสามารถทดสอบด้วย
Arch Stanton

คำตอบ:


177

นี่เป็นบิตของการแฮ็ค:

for last; do true; done
echo $last

อันนี้ก็พกพาสะดวก (อีกครั้งควรทำงานกับ bash, ksh และ sh) และมันไม่เปลี่ยนการขัดแย้งซึ่งอาจจะดี

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


10
@ MichałŠrajerฉันคิดว่าคุณหมายถึงโคลอนและไม่ใช่เครื่องหมายจุลภาค;)
Paweł Nadolski


4
ด้วย Solaris เก่าที่มี bourne shell เก่า (ไม่ใช่ POSIX) ฉันต้องเขียน "เป็นครั้งสุดท้ายใน" $ @ "; ทำจริง; เสร็จแล้ว"
mcoolive

8
@mcoolive @LaurenceGolsalves นอกจากการพกพาได้มากขึ้นแล้วfor last in "$@"; do :; doneยังทำให้ความตั้งใจชัดเจนยิ่งขึ้น
Adrian Günter

1
@coolive: มันใช้งานได้ใน unix v7 bourne shell จากปี 1979 คุณไม่สามารถพกพาได้มากขึ้นถ้ามันทำงานได้ทั้งบน v7 sh และ POSIX sh :)
Dominik R

291

นี่คือ Bash-only:

echo "${@: -1}"

43
สำหรับผู้ที่ (เช่นฉัน) สงสัยว่าทำไมพื้นที่จำเป็นมนุษย์ทุบตีได้พูดเกี่ยวกับมัน:> โปรดทราบว่าการชดเชยเชิงลบจะต้องแยกออกจากลำไส้ใหญ่อย่างน้อยหนึ่งช่องว่างเพื่อหลีกเลี่ยงการสับสนกับ: - การขยายตัว
foo

1
ฉันเคยใช้สิ่งนี้และมันจะแตกใน MSYS2 ทุบตีใน windows เท่านั้น แปลกประหลาด
Steven Lu

2
หมายเหตุ:คำตอบนี้ผลงานทั้งหมดอาร์เรย์ทุบตีซึ่งแตกต่างจากที่เพียงทำงานบน${@:$#} $@หากคุณกำลังจะคัดลอก$@ไปยังอาร์เรย์ใหม่ที่มีarr=("$@"), ${arr[@]:$#}จะไม่ได้กำหนด นี่เป็นเพราะ$@มีองค์ประกอบที่ 0 ที่ไม่รวมอยู่ในส่วน"$@"ขยาย
Mr. Llama

@ Mr.Llama: อีกที่ที่ควรหลีกเลี่ยง$#คือเมื่อทำการวนซ้ำอาร์เรย์ตั้งแต่ใน Bash อาร์เรย์จะกระจัดกระจายและในขณะที่$#จะแสดงจำนวนองค์ประกอบในอาร์เรย์มันไม่จำเป็นต้องชี้ไปที่องค์ประกอบสุดท้าย (หรือองค์ประกอบ + 1) กล่าวอีกนัยหนึ่งไม่ควรทำfor ((i = 0; i++; i < $#)); do something "${array[$i]}"; doneและทำfor element in "${array[@]}"; do something "$element"; doneซ้ำหรือทำซ้ำมากกว่าดัชนี: for index in "${!array[@]}"; do something "$index" "${array[$index]}"; doneถ้าคุณต้องการทำบางสิ่งบางอย่างกับค่าของดัชนี
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

80
$ set quick brown fox jumps

$ echo ${*: -1:1} # last argument
jumps

$ echo ${*: -1} # or simply
jumps

$ echo ${*: -2:1} # next to last
fox

พื้นที่ที่มีความจำเป็นเพื่อที่จะไม่ได้รับการตีความว่าเป็นค่าเริ่มต้น

โปรดทราบว่านี่เป็น bash-only


9
คำตอบที่ดีที่สุดเพราะมันยังรวมถึง ARG ถัดไปล่าสุด ขอบคุณ!
e40

1
สตีเว่นฉันไม่รู้ว่าคุณทำอะไรลงไปในกล่องโทษ แต่ฉันรักงานของคุณที่นี่
Bruno Bronosky

4
ใช่. เพียงแค่ดีที่สุด ทั้งหมดยกเว้นคำสั่งและอาร์กิวเมนต์สุดท้าย ${@: 1:$#-1}
Dyno Fu

1
@DynoFu ขอบคุณที่คุณตอบคำถามต่อไปของฉัน ดังนั้นการเปลี่ยนแปลงอาจดูเหมือน: echo ${@: -1} ${@: 1:$#-1}ที่สุดท้ายกลายเป็นครั้งแรกและส่วนที่เหลือเลื่อนลง
ไมค์

73

คำตอบที่ง่ายที่สุดสำหรับ bash 3.0 หรือสูงกว่าคือ

_last=${!#}       # *indirect reference* to the $# variable
# or
_last=$BASH_ARGV  # official built-in (but takes more typing :)

แค่นั้นแหละ.

$ cat lastarg
#!/bin/bash
# echo the last arg given:
_last=${!#}
echo $_last
_last=$BASH_ARGV
echo $_last
for x; do
   echo $x
done

ผลลัพธ์คือ:

$ lastarg 1 2 3 4 "5 6 7"
5 6 7
5 6 7
1
2
3
4
5 6 7

1
$BASH_ARGVไม่ทำงานในฟังก์ชันทุบตี (ยกเว้นว่าฉันกำลังทำอะไรผิด)
บิ๊ก McLargeHuge

1
BASH_ARGV มีอาร์กิวเมนต์เมื่อ bash ถูกเรียก (หรือไปยังฟังก์ชัน) ไม่ใช่รายการอาร์กิวเมนต์ที่มีอยู่ในปัจจุบัน
ไอแซค

โปรดสังเกตด้วยว่าสิ่งที่BASH_ARGVคุณจะได้รับคือคุณค่าที่อาร์กิวเมนต์สุดท้ายที่ได้รับคือแทนที่จะเป็น "ค่าสุดท้าย" ตัวอย่างเช่น!: หากคุณระบุอาร์กิวเมนต์เดียวคุณจะเรียก shift ไม่${@:$#}สร้างอะไรเลย (เพราะคุณเลื่อนอาร์กิวเมนต์หนึ่งข้อไปเท่านั้น!) อย่างไรก็ตามBASH_ARGVจะให้อาร์กิวเมนต์สุดท้าย (เดิม)
Steven Lu


29

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

${@:$#} 

ตัวอย่าง:

function afunction{
    echo ${@:$#} 
}
afunction -d -o local 50
#Outputs 50

โปรดทราบว่านี่เป็น bash-only


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

1
และมันก็ไม่แฮ็ก มันใช้คุณสมบัติที่ชัดเจนของภาษาไม่ใช่ผลข้างเคียงหรือ qwerks พิเศษ นี่ควรเป็นคำตอบที่ยอมรับได้
musicin3d

25

พบสิ่งนี้เมื่อมองหาเพื่อแยกอาร์กิวเมนต์สุดท้ายจากทั้งหมดก่อนหน้านี้ ในขณะที่บางคำตอบจะได้รับการโต้แย้งครั้งสุดท้ายพวกเขาไม่ได้ช่วยอะไรมากมายหากคุณต้องการสิ่งอื่น ๆ เช่นกัน วิธีนี้ใช้งานได้ดีกว่ามาก:

heads=${@:1:$#-1}
tail=${@:$#}

โปรดทราบว่านี่เป็น bash-only


3
คำตอบที่สตีเว่นเพนนีเป็นดีกว่าบิต: ใช้${@: -1}สำหรับที่ผ่านมาและ${@: -2:1}สำหรับวินาทีสุดท้าย (และอื่น ๆ ... ) ตัวอย่าง: การพิมพ์bash -c 'echo ${@: -1}' prog 0 1 2 3 4 5 6 6ที่จะอยู่กับวิธีการของ AgileZebra ปัจจุบันนี้การใช้งาน${@:$#-1:1}ที่จะได้รับวินาทีสุดท้าย ตัวอย่าง: การพิมพ์bash -c 'echo ${@:$#-1:1}' prog 0 1 2 3 4 5 6 5(และ${@:$#-2:1}เพื่อให้ได้อันดับสามเป็นต้นไป ... )
olibre

4
คำตอบของ AgileZebra ให้วิธีการรับทั้งหมด แต่ข้อโต้แย้งสุดท้ายดังนั้นฉันจะไม่พูดคำตอบของ Steven แทนมัน แต่ดูเหมือนว่าจะมีเหตุผลที่จะใช้$((...))ในการลบ 1 ${@:1:$# - 1}คุณก็สามารถใช้
dkasak

ขอบคุณ dkasak อัปเดตเพื่อสะท้อนความเรียบง่ายของคุณ
AgileZebra

22

สิ่งนี้ใช้ได้กับเชลล์ที่ใช้ POSIX ได้ทั้งหมด:

eval last=\${$#}

ที่มา: http://www.faqs.org/faqs/unix-faq/faq/part2/section-12.html


2
ดูความคิดเห็นนี้ที่แนบมากับคำตอบที่เหมือนกันที่มีอายุมากกว่า
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

1
โซลูชันแบบพกพาที่ง่ายที่สุดที่ฉันเห็นที่นี่ อันนี้ไม่มีปัญหาด้านความปลอดภัย @DennisWilliamson การอ้างอิงเชิงประจักษ์ดูเหมือนว่าจะถูกต้องเว้นแต่จะมีวิธีตั้งค่า$#สตริงโดยพลการ (ฉันไม่คิดอย่างนั้น) eval last=\"\${$#}\"ยังใช้งานได้และถูกต้องชัดเจน ไม่เห็นเหตุผลที่ไม่จำเป็นต้องใช้คำพูด
Palec

1
สำหรับbash , zsh , dashและksh eval last=\"\${$#}\"นั้นใช้ได้ แต่สำหรับcshและtcsheval set last=\"\${$#}\"ใช้ ดูตัวอย่างนี้: tcsh -c 'eval set last=\"\${$#}\"; echo "$last"' arg1 arg2 arg3.
olibre

12

นี่คือทางออกของฉัน:

  • แบบพกพาสวย (POSIX sh, ทุบตี, ksh, zsh) ทั้งหมดควรทำงาน
  • ไม่เปลี่ยนอาร์กิวเมนต์เดิม (เลื่อนสำเนา)
  • ไม่ใช้ความชั่วร้าย eval
  • ไม่ได้วนซ้ำทั้งรายการ
  • ไม่ใช้เครื่องมือภายนอก

รหัส:

ntharg() {
    shift $1
    printf '%s\n' "$1"
}
LAST_ARG=`ntharg $# "$@"`

1
คำตอบที่ดี - สั้นพกพาปลอดภัย ขอบคุณ!
JánLalinský

2
นี่เป็นความคิดที่ดี แต่ฉันมีข้อเสนอแนะสองสามข้อประการแรกควรเพิ่มข้อความทั้งสองรอบ"$1"และ"$#"(ดูคำตอบที่ยอดเยี่ยมนี้unix.stackexchange.com/a/171347 ) ประการที่สองechoเป็นเรื่องเศร้าที่ไม่ใช่พกพา (โดยเฉพาะสำหรับ-n) ดังนั้นprintf '%s\n' "$1"ควรใช้แทน
joki

ขอบคุณ @joki ฉันทำงานกับระบบยูนิกซ์ที่แตกต่างกันและฉันก็ไม่ไว้ใจecho -nเช่นecho "$1"กัน อย่างไรก็ตามprintfสามารถคาดเดาได้มากขึ้น - อัปเดต
MichałŠrajer

@ MichałŠrajerพิจารณากรณีที่ "$ 1" คือ "-n" หรือ "-" ดังนั้นตัวอย่างเช่นntharg 1 -nหรือntharg 1 --อาจให้ผลลัพธ์ที่แตกต่างกันในระบบต่างๆ รหัสที่คุณมีตอนนี้ปลอดภัย!
joki

10

จากโซลูชันที่เก่าที่สุดถึงใหม่กว่า:

โซลูชันแบบพกพาที่สุดแม้เก่ากว่าsh(ใช้ได้กับช่องว่างและอักขระกลม) (ไม่วนซ้ำเร็วกว่า):

eval printf "'%s\n'" "\"\${$#}\""

ตั้งแต่เวอร์ชั่น 2.01 ของการทุบตี

$ set -- The quick brown fox jumps over the lazy dog

$ printf '%s\n'     "${!#}     ${@:(-1)} ${@: -1} ${@:~0} ${!#}"
dog     dog dog dog dog

สำหรับ ksh, zsh และ bash:

$ printf '%s\n' "${@: -1}    ${@:~0}"     # the space beetwen `:`
                                          # and `-1` is a must.
dog   dog

และสำหรับ "ถัดจากหน้าสุดท้าย":

$ printf '%s\n' "${@:~1:1}"
lazy

การใช้ printf เพื่อแก้ไขปัญหาใด ๆ ที่เกิดขึ้นกับอาร์กิวเมนต์ที่ขึ้นต้นด้วยเส้นประ (เช่น -n )

สำหรับเชลล์ทั้งหมดและเก่ากว่าsh(ใช้ได้กับช่องว่างและอักขระกลม) คือ:

$ set -- The quick brown fox jumps over the lazy dog "the * last argument"

$ eval printf "'%s\n'" "\"\${$#}\""
The last * argument

หรือหากคุณต้องการตั้งค่าlastvar:

$ eval last=\${$#}; printf '%s\n' "$last"
The last * argument

และสำหรับ "ถัดจากหน้าสุดท้าย":

$ eval printf "'%s\n'" "\"\${$(($#-1))}\""
dog

8

หากคุณกำลังใช้ Bash> = 3.0

echo ${BASH_ARGV[0]}

นอกจากนี้สำหรับข้อโต้แย้งถัดไปให้ทำecho ${BASH_ARGV[1]}
Steven Penny

1
ARGVหมายถึง "อาร์กิวเมนต์เวกเตอร์"
Serge Stroobandt


3
shift `expr $# - 1`
echo "$1"

สิ่งนี้จะเปลี่ยนอาร์กิวเมนต์ด้วยจำนวนอาร์กิวเมนต์ลบ 1 และส่งกลับอาร์กิวเมนต์แรกที่เหลือ (และเท่านั้น) ซึ่งจะเป็นอาร์กิวเมนต์สุดท้าย

ฉันทดสอบใน bash เท่านั้น แต่ควรใช้ sh และ ksh ด้วย


11
shift $(($# - 1))- ไม่จำเป็นต้องมียูทิลิตี้ภายนอก ใช้งานได้ใน Bash, ksh, zsh และ dash
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

@Dennis: ดี! ฉันไม่รู้เกี่ยวกับ$((...))ไวยากรณ์
Laurence Gonsalves

คุณต้องการใช้printf '%s\n' "$1"เพื่อหลีกเลี่ยงพฤติกรรมที่ไม่คาดคิดecho(เช่นเพื่อ-n)
joki

2

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

#!/bin/bash

last() {
        if [[ $# -ne 0 ]] ; then
            shift $(expr $# - 1)
            echo "$1"
        #else
            #do something when no arguments
        fi
}

lastvar=$(last "$@")
echo $lastvar
echo "$@"

pax> ./qq.sh 1 2 3 a b
b
1 2 3 a b

ถ้าคุณไม่สนใจจริง ๆเกี่ยวกับการรักษาข้อโต้แย้งอื่น ๆ คุณไม่จำเป็นต้องใช้มันในฟังก์ชั่น แต่ฉันมีความลำบากในการคิดสถานการณ์ที่คุณจะไม่ต้องการเก็บข้อโต้แย้งอื่น ๆ จนกว่าพวกเขาจะถูกประมวลผลแล้ว ในกรณีนี้ฉันจะใช้กระบวนการ / shift / process / shift / ... วิธีการประมวลผลตามลำดับ

ฉันสมมุติว่าคุณต้องการเก็บไว้เพราะคุณไม่ได้ทำตามวิธีการเรียงลำดับ วิธีนี้ยังจัดการกรณีที่ไม่มีข้อโต้แย้งส่งคืน "" คุณสามารถจะปรับพฤติกรรมโดยการใส่ความเห็นออกelseข้อ


2

สำหรับ tcsh:

set X = `echo $* | awk -F " " '{print $NF}'`
somecommand "$X"

ฉันค่อนข้างแน่ใจว่านี่จะเป็นโซลูชันแบบพกพายกเว้นการมอบหมาย


ฉันรู้ว่าคุณโพสต์นี้ตลอดไปแล้ว แต่วิธีนี้ดีมาก - ดีใจที่มีคนโพสต์ tcsh!
user3295674

2

ฉันพบคำตอบของ @ AgileZebra (บวกกับความคิดเห็นของ @ starfry) มีประโยชน์มากที่สุด แต่มันตั้งค่าheadsเป็นสเกลาร์ อาเรย์นั้นมีประโยชน์มากกว่า:

heads=( "${@:1:$(($# - 1))}" )
tail=${@:${#@}}

โปรดทราบว่านี่เป็น bash-only


คุณจะแปลงหัวเป็นอาร์เรย์ได้อย่างไร?
Stephane

ฉันแล้วได้โดยการเพิ่มวงเล็บเช่นพิมพ์องค์ประกอบสุดท้ายในecho "${heads[-1]}" headsหรือว่าฉันขาดอะไรไป?
EndlosSchleife

1

วิธีใช้eval:

last=$(eval "echo \$$#")

echo $last

7
eval สำหรับการอ้างอิงทางอ้อมคือ overkill ไม่พูดถึงการปฏิบัติที่ไม่ดีและความกังวลด้านความปลอดภัยขนาดใหญ่ (ค่าไม่ได้อ้างอิงใน echo หรือนอก $ () Bash มีไวยากรณ์ในตัวสำหรับการอ้างอิงทางอ้อมสำหรับ var ใด ๆ : !ดังนั้นlast="${!#}"จะใช้เหมือนกัน เข้าหา (การอ้างอิงทางอ้อมใน $ #) ด้วยวิธีที่ปลอดภัย, กะทัดรัด, builtin, sane way และอ้างถึงอย่างถูกต้อง
MestreLion

ดูวิธีการทำความสะอาดเพื่อดำเนินการเดียวกันในคำตอบอื่น
Palec

@MestreLion คำพูดที่ไม่จำเป็นบน RHS =ของ
Tom Hale

1
@TomHale: จริงสำหรับกรณีเฉพาะของ${!#}แต่ไม่ได้โดยทั่วไป: last='two words'คำพูดที่ยังคงมีความจำเป็นหากเนื้อหามีช่องว่างที่แท้จริงเช่น เพียง แต่$()เป็นช่องว่างที่ปลอดภัยไม่คำนึงถึงเนื้อหา
MestreLion

1

หลังจากอ่านคำตอบข้างต้นฉันได้เขียนเชลล์สคริปต์ Q&D (ควรใช้ sh และ bash) เพื่อรัน g ++ บน PGM.cpp เพื่อสร้างอิมเมจที่ปฏิบัติการได้ PGM จะถือว่าอาร์กิวเมนต์สุดท้ายของบรรทัดคำสั่งคือชื่อไฟล์ (.cpp เป็นทางเลือก) และอาร์กิวเมนต์อื่นทั้งหมดเป็นตัวเลือก

#!/bin/sh
if [ $# -lt 1 ]
then
    echo "Usage: `basename $0` [opt] pgm runs g++ to compile pgm[.cpp] into pgm"
    exit 2
fi
OPT=
PGM=
# PGM is the last argument, all others are considered options
for F; do OPT="$OPT $PGM"; PGM=$F; done
DIR=`dirname $PGM`
PGM=`basename $PGM .cpp`
# put -o first so it can be overridden by -o specified in OPT
set -x
g++ -o $DIR/$PGM $OPT $DIR/$PGM.cpp

1

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

LAST=$({
   shift $(($#-1))
   echo $1
})
echo $LAST

หากไม่มีข้อโต้แย้งอื่น ๆ อีกต่อไปและสามารถเปลี่ยนได้

shift $(($#-1))
echo $1

สำหรับเหตุผลในการพกพาต่อไปนี้:

shift $(($#-1));

สามารถถูกแทนที่ด้วย:

shift `expr $# - 1`

การแทนที่$()ด้วย backquotes ที่เราได้รับ:

LAST=`{
   shift \`expr $# - 1\`
   echo $1
}`
echo $LAST

1
echo $argv[$#argv]

ตอนนี้ฉันแค่ต้องเพิ่มข้อความเพราะคำตอบของฉันสั้นเกินไปที่จะโพสต์ ฉันต้องการเพิ่มข้อความเพิ่มเติมเพื่อแก้ไข


เปลือกหอยตัวไหนที่ใช้งานได้? ไม่ทุบตี ไม่ใช่ปลา (มี$argvแต่ไม่ใช่$#argv- $argv[(count $argv)]ใช้ได้กับปลา)
Beni Cherniavsky-Paskin

1

นี่เป็นส่วนหนึ่งของฟังก์ชั่นการคัดลอกของฉัน:

eval echo $(echo '$'"$#")

หากต้องการใช้ในสคริปต์ให้ทำสิ่งนี้:

a=$(eval echo $(echo '$'"$#"))

คำอธิบาย (ซ้อนกันมากที่สุดก่อน):

  1. $(echo '$'"$#")ส่งคืน$[nr]โดยที่[nr]เป็นจำนวนพารามิเตอร์ เช่นสตริง$123(ไม่ขยาย)
  2. echo $123 ส่งคืนค่าพารามิเตอร์ 123rd เมื่อประเมินผล
  3. evalเพียงแค่ขยายมูลค่าของพารามิเตอร์เช่น$123 last_argสิ่งนี้ถูกตีความว่าเป็นสตริงและส่งคืน

ทำงานร่วมกับ Bash เมื่อกลางปี ​​2558


วิธีการประเมินผลได้ถูกนำเสนอที่นี่หลายครั้งแล้ว แต่วิธีนี้มีคำอธิบายเกี่ยวกับวิธีการทำงาน ควรปรับปรุงเพิ่มเติม แต่ก็ยังคุ้มค่า
Palec

0
#! /bin/sh

next=$1
while [ -n "${next}" ] ; do
  last=$next
  shift
  next=$1
done

echo $last

สิ่งนี้จะล้มเหลวหากอาร์กิวเมนต์เป็นสตริงว่าง แต่จะทำงานใน 99.9% ของเคส
โทมัส

0

ลองใช้สคริปต์ด้านล่างเพื่อค้นหาอาร์กิวเมนต์ล่าสุด

 # cat arguments.sh
 #!/bin/bash
 if [ $# -eq 0 ]
 then
 echo "No Arguments supplied"
 else
 echo $* > .ags
 sed -e 's/ /\n/g' .ags | tac | head -n1 > .ga
 echo "Last Argument is: `cat .ga`"
 fi

เอาท์พุท:

 # ./arguments.sh
 No Arguments supplied

 # ./arguments.sh testing for the last argument value
 Last Argument is: value

ขอบคุณ


ฉันสงสัยว่าสิ่งนี้จะล้มเหลวด้วย. / arguments.sh "ค่าสุดท้าย"
โทมัส

ขอบคุณสำหรับการตรวจสอบโทมัสฉันได้พยายามที่จะดำเนินการตามสคริปต์เช่นคุณ mentinoed # ./arguments.sh "ค่าสุดท้าย" อาร์กิวเมนต์สุดท้ายคือ: ค่าทำงานได้ดีในขณะนี้ # ./arguments.sh "ตรวจสอบค่าสุดท้ายด้วย double" อาร์กิวเมนต์สุดท้ายคือ: double
Ranjithkumar T

ปัญหาคืออาร์กิวเมนต์สุดท้ายคือ 'ค่าสุดท้าย' และไม่ใช่ค่า ข้อผิดพลาดเกิดจากการโต้แย้งที่มีช่องว่าง
โทมัส

0

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

  argArray=( "$@" )                        # Add all script arguments to argArray
  arrayLength=${#argArray[@]}              # Get the length of the array
  lastArg=$((arrayLength - 1))             # Arrays are zero based, so last arg is -1
  echo ${argArray[$lastArg]}

ตัวอย่างผลลัพธ์

$ ./lastarg.sh 1 2 buckle my shoe
shoe

0

ใช้การขยายพารามิเตอร์ (ลบการเริ่มต้นตรง):

args="$@"
last=${args##* }

นอกจากนี้ยังง่ายที่จะได้รับทั้งหมดก่อนหน้านี้:

prelast=${args% *}

เป็นไปได้ (แย่) ซ้ำซ้อนของstackoverflow.com/a/37601842/1446229
Xerz

ใช้งานได้เฉพาะถ้าอาร์กิวเมนต์สุดท้ายไม่มีช่องว่าง
Palec

ตัวเลือกแรกของคุณล้มเหลวหากอาร์กิวเมนต์สุดท้ายเป็นประโยคที่อยู่ในเครื่องหมายคำพูดคู่โดยที่ประโยคดังกล่าวควรเป็นอาร์กิวเมนต์เดียว
Stephane

0

ในการส่งคืนอาร์กิวเมนต์ล่าสุดของคำสั่งที่ใช้ล่าสุดให้ใช้พารามิเตอร์พิเศษ:

$_

ในกรณีนี้มันจะทำงานถ้ามันถูกใช้ภายในสคริปต์ก่อนที่คำสั่งอื่นจะถูกเรียก


นี่ไม่ใช่คำถามที่ถาม
ตอบเมื่อ

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