ตรวจสอบว่าพารามิเตอร์ใด ๆ กับสคริปต์ทุบตีตรงกับสตริงหรือไม่


67

ฉันพยายามเขียนสคริปต์ที่ฉันต้องการตรวจสอบว่าพารามิเตอร์ใด ๆ ที่ส่งผ่านไปยังสคริปต์ทุบตีตรงกับสตริง วิธีที่ฉันตั้งค่าตอนนี้ก็คือ

if [ "$3" != "-disCopperBld" -a "$4" != "-disCopperBld" -a "$5" != "-disCopperBld" -a "$6" != "-disCopperBld"]

แต่อาจมีพารามิเตอร์จำนวนมากดังนั้นฉันสงสัยว่ามีวิธีที่ดีกว่าในการทำเช่นนี้หรือไม่

ขอบคุณ

แก้ไข: ฉันลองใช้โค๊ดของโค้ดนี้และเรียกสคริปต์ด้วยตัวเลือก -disableVenusBld แต่มันก็ยังพิมพ์ "เริ่มต้นบิลด์" ฉันกำลังทำอะไรผิดหรือเปล่า? ขอบคุณล่วงหน้า!

while [ $# -ne 0 ]
do
    arg="$1"
    case "$arg" in
        -disableVenusBld)
            disableVenusBld=true
            ;;
        -disableCopperBld)
            disableCopperBld=true
            ;;
        -disableTest)
            disableTest=true
            ;;
        -disableUpdate)
            disableUpdate=true
            ;;
        *)
            nothing="true"
            ;;
    esac
    shift
done

if [ "$disableVenusBld" != true ]; then
    echo "Starting build"
fi

ขอบคุณสำหรับคำตอบพวกฉันขอบคุณที่คุณสละเวลาเพื่อช่วยฉัน ฉันลองใช้รหัส แต่ฉันไม่สามารถเข้าใจได้ว่าเกิดอะไรขึ้น ความคิดใด ๆ (ผมเคยวางรหัสในการแก้ไขของโพสต์เดิมของฉันนั้น)
iman453

อืม: มันใช้งานได้สำหรับฉัน ฉันเพิ่มลง#! /bin/sh -ในส่วนบนสุดของสิ่งที่คุณรวมไว้แล้วทำให้สคริปต์ทำงานได้จากนั้น./t.shพิมพ์ "เริ่มสร้าง" แต่./t.sh -disableVenusBldไม่พิมพ์อะไรเลย
Norman Grey

คำตอบ:


59

ดูเหมือนว่าคุณกำลังจัดการตัวเลือกในเชลล์สคริปต์ นี่คือสำนวนที่:

#! /bin/sh -

# idiomatic parameter and option handling in sh
while test $# -gt 0
do
    case "$1" in
        --opt1) echo "option 1"
            ;;
        --opt2) echo "option 2"
            ;;
        --*) echo "bad option $1"
            ;;
        *) echo "argument $1"
            ;;
    esac
    shift
done

exit 0

(มีข้อตกลงสองสามข้อสำหรับการเยื้อง;;และเชลล์บางตัวอนุญาตให้คุณกำหนดตัวเลือก(--opt1)เพื่อช่วยในการจับคู่รั้ง แต่นี่เป็นแนวคิดพื้นฐาน)


3
shiftคำสั่งจะใช้เมื่อจำนวนของการขัดแย้งกับคำสั่งที่ไม่เป็นที่รู้จักล่วงหน้าตัวอย่างเช่นเมื่อผู้ใช้สามารถให้การขัดแย้งให้มากที่สุดเท่าที่พวกเขาต้องการ ในกรณีดังกล่าวข้อโต้แย้งที่มีการประมวลผลในวงกับสภาพการทดสอบของwhile $#เงื่อนไขนี้เป็นจริงตราบใดที่จำนวนอาร์กิวเมนต์มากกว่าศูนย์ $1ตัวแปรและshiftกระบวนการคำสั่งแต่ละอาร์กิวเมนต์ จำนวนข้อโต้แย้งจะลดลงทุกครั้งที่shiftมีการดำเนินการและในที่สุดก็กลายเป็นศูนย์ตามที่whileวงออกจาก แหล่งที่มา
Serge Stroobandt

นี่เป็นตัวอย่างที่คล้ายกันด้วยเพิ่มเติมประมวลผลค่าอาร์กิวเมนต์echo $1 | sed
Serge Stroobandt

26

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

if [[ "$*" == *YOURSTRING* ]]
then
    echo "YES"
else
    echo "NO"
fi

สิ่งนี้ใช้ประโยชน์จากการจัดการพิเศษ$* และการทุบ super-test [[]]brackets


2
IMHO จะต้องเป็นคำตอบที่ถูกต้องที่สุดเนื่องจากคำถามนั้นต้องการเพียงเพื่อตรวจสอบว่ามีพารามิเตอร์หรือไม่ ฉันได้แก้ไข แต่เปลี่ยน$*ไป$@ตั้งแต่สตริงเพื่อจะทดสอบอาจจะมีช่องว่างและเพิ่มเชื่อมโยงไปยังเอกสารทุบตีเกี่ยวกับมัน
h7r

9
คุณหมายถึงใช้ตัวดำเนินการ = ~ หรือไม่ มิฉะนั้นฉันไม่เห็นว่าทำไมสิ่งนี้ถึงได้ผลและแน่นอนว่ามันไม่ทำงานเมื่อฉันลองใช้สคริปต์ที่แน่นอน
Seppo Enarvi

3
ไม่ทำงาน. bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
Tobia

2
your stringนี้เปรียบเทียบรายการอาร์กิวเมนต์ทั้งหมดที่มี ฉันคิดว่าคุณต้องทำในสิ่งที่เป็นข้อเสนอแนะจากคำตอบนี้ เช่น: bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar fooจะทำงาน
starfry

2
คำตอบนี้ผิดในช่วงสี่ปีที่ผ่านมาเนื่องจากการแก้ไข h7r ทำลาย คำตอบดั้งเดิม (ซึ่งตอนนี้ฉันได้คืนค่าแล้ว) ทำงานโดยมี“ สตริงของคุณ” ไม่มีอักขระกลมและมีผลบวกบางอย่าง ตัวอย่างเช่นถ้าคำสั่งcreate a new certificateและ“สายของคุณ” เป็นcatนี้จะรายงานการแข่งขันเพราะมีcertificate cat
สกอตต์

8

วิธีการค้นหา (ด้วย wildcard) พื้นที่พารามิเตอร์ทั้งหมด:

if [[ $@ == *'-disableVenusBld'* ]]
then

แก้ไข: ตกลงตกลงดังนั้นจึงไม่ใช่คำตอบที่ได้รับความนิยม แล้วอันนี้ก็สมบูรณ์แบบ!:

if [[ "${@#-disableVenusBld}" = "$@" ]]
then
    echo "Did not find disableVenusBld"
else
    echo "Found disableVenusBld"
fi

แก้ไข 2: โอเคโอเคบางทีมันอาจไม่สมบูรณ์แบบ ... คิดว่ามันจะใช้ได้เฉพาะในกรณีที่ -param เป็นจุดเริ่มต้นของรายการและจะจับคู่กับ -paramXZY หรือ -paramABC ฉันยังคงคิดว่าปัญหาดั้งเดิมสามารถแก้ไขได้อย่างดีกับการจัดการสตริงของ bash แต่ฉันไม่ได้ถอดรหัสที่นี่ ...


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

คุณช่วยอธิบายว่าคำแนะนำที่สอง (โดยเฉพาะ${@#) ทำอะไรได้บ้าง?
velop

1
@velop แน่นอน! ดังนั้นคุณจะรู้ว่า$@เป็นตัวแปรพิเศษที่เก็บอาร์กิวเมนต์บรรทัดคำสั่งทั้งหมดหรือไม่ ดีที่ผมเคยใช้เพียงแค่ทุบตีจัดการสตริงในตัวแปรที่จะเอาย่อย "-disableVenusBld" $@และจากนั้นผมเปรียบเทียบกับต้นฉบับ ดังนั้นถ้า$@เท่ากับ-foo -barแล้ว${@#-disableVenusBld}จะยังคงอยู่-foo -barดังนั้นฉันจะเห็นว่าธงฉันกำลังมองหาไม่เป็นปัจจุบัน อย่างไรก็ตามถ้า$@เท่ากับ-foo -disableVenusBld -barแล้ว${@#-disableVenusBld}จะ-foo -barไม่เท่ากับ$@ดังนั้นบอกฉันว่าธงที่ฉันกำลังมองหาอยู่! เจ๋งเอ๊ะ!
รวย

@velop เรียนรู้เพิ่มเติมเกี่ยวกับการจัดการสตริงของ Bash ที่นี่: tldp.org/LDP/abs/html/string-manipulation.html
Rich

@ Rich ค่อนข้างเรียบร้อย ^^ ขอบคุณสำหรับคำอธิบาย
velop

4
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

หากคุณต้องการทดสอบเฉพาะพารามิเตอร์ที่เริ่มต้น$3ให้ทำการค้นหาในฟังก์ชั่น:

## Usage: search_trailing_parameters NEEDLE NUM "$@"
## Search NEEDLE amongst the parameters, skipping $1 through ${$NUM}.
search_trailing_parameters () {
  needle=$1
  shift $(($2 + 2))
  for x; do
    if [ "$x" = "$needle" ]; then return 0; fi
  done
  return 1
}
if search_trailing_parameters -disCopperBld 2 "$@"; then
  ...
fi

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

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