ประมวลผลอาร์กิวเมนต์ทั้งหมดยกเว้นอาร์กิวเมนต์แรก (ในสคริปต์ทุบตี)


444

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

เมื่อใช้ Google ฉันพบวิกินี้แต่มีตัวอย่างจริง:

echo "${@: -1}"

ฉันไม่สามารถทำงานอย่างอื่นได้เช่น:

echo "${@:2}"

หรือ

echo "${@:2,1}"

ฉันได้รับ "การทดแทนไม่ดี" จากเทอร์มินัล

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


21
หากต้องการโทรออกเพื่อคนอื่นทำให้สับสน Shebang ที่ไม่ถูกต้องนั้นทำให้"{@:2}"ไม่ทำงานซึ่งเป็นสาเหตุที่คำตอบที่ถูกต้องตรงกัน
Guvante

3
คุณเพิ่งใช้เชลล์เริ่มต้นซึ่งเป็นเส้นประบน Ubuntu และ Linux อื่น ๆ ในเส้นประ "$ {@: -1}" ถูกตีความว่าเป็น: {พารามิเตอร์: -word} - ใช้ค่าเริ่มต้นและใช้คำหากพารามิเตอร์ไม่ได้กำหนดหรือเป็นโมฆะ ดังนั้นในเส้นประ "$ {@: -1}" จะให้ผลลัพธ์เหมือนกับ "$ @" ในการใช้ bash ให้ใช้บรรทัดแรกต่อไปนี้ในไฟล์สคริปต์: #! / bin / bash
luart

คำตอบ:


660

ใช้สิ่งนี้:

echo "${@:2}"

ไวยากรณ์ต่อไปนี้:

echo "${*:2}"

จะทำงานได้ดี แต่ไม่แนะนำเพราะตามที่@Gordonได้อธิบายไว้แล้วว่าการใช้*มันจะเรียกใช้อาร์กิวเมนต์ทั้งหมดพร้อมกันเป็นอาร์กิวเมนต์เดียวที่มีช่องว่างในขณะที่@รักษาตัวแบ่งระหว่างพวกเขา (แม้ว่าอาร์กิวเมนต์บางตัวจะมีช่องว่าง ) มันไม่ได้สร้างความแตกต่างด้วยechoแต่มันสำคัญสำหรับคำสั่งอื่น ๆ


7
ฉันเพิ่งรู้ว่า Shebang ของฉันไม่ดี: #!/usr/bin/env shนั่นเป็นสาเหตุที่ฉันมีปัญหา ตัวอย่างเช่นคุณทำงานได้ดีเช่นเดียวกับที่ให้ไว้หลังจากที่ฉันลบ Shebang
theta

110
ใช้"${@:2}"แทน - การใช้*รันอาร์กิวเมนต์ทั้งหมดพร้อมกันเป็นอาร์กิวเมนต์เดียวพร้อมช่องว่างในขณะที่@รักษาการหยุดพักระหว่างพวกเขา (แม้ว่าบางอาร์กิวเมนต์จะมีช่องว่าง) ความแตกต่างนั้นไม่เห็นได้ชัดเจนechoแต่มันมีความสำคัญสำหรับสิ่งอื่น ๆ
Gordon Davisson

2
@GordonDavisson จุดทั้งหมดที่นี่คือการเรียกใช้อาร์กิวเมนต์ด้วยกัน หากเราผ่านชื่อไฟล์คุณจะถูกต้อง echoให้อภัยมากพอที่จะต่อพวกเขาให้คุณ; คำสั่งอื่นอาจไม่ดีนัก อย่าใช้อย่างใดอย่างหนึ่ง: เรียนรู้ความแตกต่างระหว่าง*และ@และเมื่อใช้กัน คุณควรใช้พวกเขาอย่างเท่าเทียมกัน ตัวอย่างที่ดีว่าจะเกิดปัญหาเมื่อ: หาก$3มีตัวแบ่งบรรทัด ( \n) จะถูกแทนที่ด้วยช่องว่างหากคุณมี$IFSตัวแปรเริ่มต้น
Zenexer

1
@ Zenexer: เมื่อฉันเข้าใจแล้วคำถามก็คือทำอย่างไรจึงจะส่งผ่านทั้งหมดยกเว้นอาร์กิวเมนต์แรกที่ "ไปยังส่วนอื่น ๆ ของสคริปต์" โดยechoใช้เพียงตัวอย่าง - ซึ่งในกรณีนี้พวกเขาไม่ควรทำงานร่วมกัน จากประสบการณ์ของฉันสถานการณ์ที่คุณต้องการให้ทำงานร่วมกันนั้นหายาก (ดูคำถามนี้สำหรับตัวอย่างหนึ่ง ) และ"$@"เกือบจะเป็นสิ่งที่คุณต้องการเสมอ นอกจากนี้ปัญหาที่คุณพูดถึงเมื่อมีการขึ้นบรรทัดใหม่จะเกิดขึ้นก็ต่อเมื่อ$@(หรือ$*) ไม่ได้อยู่ในเครื่องหมายคำพูดคู่
Gordon Davisson

@GordonDavisson อืม ... คุณพูดถูกแล้วตอนนี้ฉันก็คิดถึงมัน ตัวแบ่งบรรทัดไม่ควรเป็นปัญหา ฉันต้องคิดอย่างอื่น อย่างไรก็ตามฉันยังคงต้องไม่เห็นด้วยกับการรวมพวกมันเข้าด้วยกัน ฉันต้องใช้$*บ่อยในสคริปต์ของฉัน
Zenexer

180

หากคุณต้องการโซลูชันที่ใช้งานได้ใน/bin/shลอง

first_arg="$1"
shift
echo First argument: "$first_arg"
echo Remaining arguments: "$@"

shift [n]เลื่อนพารามิเตอร์ตำแหน่งnครั้ง A shiftตั้งค่า$1เป็นค่าของ$2, ค่าของ$2ถึงค่าของ$3, และอื่น ๆ , ลดค่าของ$#หนึ่ง


25
+1: คุณควรบันทึก $ 1 เป็นตัวแปรก่อนจะเลื่อนออกไป
เกล็

3
น่าแปลกที่foo=shiftไม่ได้ทำในสิ่งที่ฉันคาดหวัง
Keith Smiley

ฉันรู้ว่ามันเก่า แต่ลองfoo=$(shift)
raumaan kidwai

12
@raumaankidwai นั่นใช้ไม่ได้กับ 2 เหตุผล: 1) shift(ใน shell) ไม่มีเอาต์พุตใด ๆ มันแค่ทิ้ง$1และเปลี่ยนทุกอย่างลง 2) $(...)เริ่ม subshell ซึ่งมีอาร์กิวเมนต์ในตัวของมันเอง มันเปลี่ยนการขัดแย้งใน subshell ซึ่งไม่ส่งผลกระทบต่อผู้ปกครอง
Ben Jackson

ขอบคุณ :) มีวิธีที่จะทำอะไรsomecommand "$1" "${@:2}"กับวิธีนี้ (เช่น shift "inline") แต่?
ไม่ระบุชื่อ


0

มาหาสิ่งนี้เพื่อหาสิ่งอื่น ในขณะที่โพสต์นั้นดูค่อนข้างเก่าวิธีแก้ปัญหาที่ง่ายที่สุดใน bash นั้นแสดงไว้ด้านล่าง (อย่างน้อย bash 4) โดยใช้set -- "${@:#}"ที่ # คือหมายเลขเริ่มต้นขององค์ประกอบอาร์เรย์ที่เราต้องการรักษาไว้ข้างหน้า:

    #!/bin/bash

    someVar="${1}"
    someOtherVar="${2}"
    set -- "${@:3}"
    input=${@}

    [[ "${input[*],,}" == *"someword"* ]] && someNewVar="trigger"

    echo -e "${someVar}\n${someOtherVar}\n${someNewVar}\n\n${@}"

โดยทั่วไปset -- "${@:3}"เพียงแค่โผล่ออกมาสององค์ประกอบแรกในอาร์เรย์เช่นการเปลี่ยนแปลงของ perl และรักษาองค์ประกอบที่เหลือทั้งหมดรวมทั้งที่สาม ฉันสงสัยว่าจะมีวิธีการดึงองค์ประกอบสุดท้ายออกมาเช่นกัน

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