ฉันจะเขียนเชลล์สคริปต์ที่จะทำการจับคู่สตริงย่อยที่ไม่ตรงตามตัวพิมพ์เล็กและใหญ่ของเอาต์พุตคำสั่งได้อย่างไร?
bashซึ่งเป็น superset ของมาตรฐานยูนิกซ์ shคุณอาจเริ่มด้วยการดูหนึ่งในนี้: | 1 | | 2 | - เพียงเพื่อให้ได้มาซึ่งบริบทที่แท้จริง
ฉันจะเขียนเชลล์สคริปต์ที่จะทำการจับคู่สตริงย่อยที่ไม่ตรงตามตัวพิมพ์เล็กและใหญ่ของเอาต์พุตคำสั่งได้อย่างไร?
bashซึ่งเป็น superset ของมาตรฐานยูนิกซ์ shคุณอาจเริ่มด้วยการดูหนึ่งในนี้: | 1 | | 2 | - เพียงเพื่อให้ได้มาซึ่งบริบทที่แท้จริง
คำตอบ:
ครั้งแรกที่นี่เป็นตัวอย่างสคริปต์ง่ายๆที่ไม่สนใจกรณีและปัญหา:
#!/bin/bash
if [ $(echo hello) == hello ]; then
echo it works
fi
it worksลองเปลี่ยนสวัสดีสตริงด้านขวาและมันไม่ควรสะท้อน ลองแทนที่echo helloด้วยคำสั่งที่คุณเลือก หากคุณต้องการละเว้นตัวพิมพ์ใหญ่และสตริงไม่มีทั้งตัวแบ่งบรรทัดคุณสามารถใช้ grep:
#!/bin/bash
if echo Hello | grep -iqF hello; then
echo it works
fi
grepที่สำคัญนี่คือการที่คุณจะบีบออกคำสั่งไป ifคำสั่งการทดสอบออกจากสถานะของคำสั่งขวาสุดในท่อ - ในกรณี grep นี้ Grep ออกมาพร้อมกับความสำเร็จถ้าหากพบว่ามีการแข่งขัน
-iตัวเลือกในการ grep กล่าวว่ากรณีที่จะไม่สนใจ ตัวเลือกกล่าวว่าจะไม่ส่งออกปล่อยและออกหลังจากที่นัดแรก ตัวเลือกกล่าวว่าในการรักษาอาร์กิวเมนต์เป็นสตริงมากกว่าการแสดงออกปกติ-q-F
โปรดทราบว่าตัวอย่างแรกใช้ซึ่งช่วยให้การเปรียบเทียบโดยตรงและผู้ประกอบการที่มีประโยชน์ต่างๆ รูปแบบที่สองเพียงดำเนินการคำสั่งและทดสอบสถานะการออก[ expression ]
==ไม่ใช่ POSIX shไม่ได้bashอยู่บนระบบที่ใช้ Linux ทั้งหมด ==ไม่ได้รับการสนับสนุนจากash(ขึ้นอยู่กับที่shของ BSDs จำนวนมากและสัญญาซื้อขายล่วงหน้า Debian อย่างน้อยจะขึ้น) หรือและความต้องการยกมาในposh มีจุดวกกลับไม่ได้zsh เป็นคำสั่งสำหรับการทดสอบ ไม่จำเป็นต้องแยกแยะระหว่างการมอบหมายและการเปรียบเทียบที่นี่ นั่นคือความแตกต่างในVS การใช้สคริปต์ที่ขึ้นต้นด้วยผิด หากคุณสมมติหรือไวยากรณ์ให้ปรับปรุงตามนั้น =[(( a == b ))(( a = b))==#! /bin/shkshbash#!
คุณสามารถทำการจับคู่สตริงย่อยแบบไม่ตรงตามตัวอักษรในการbashใช้โอเปอเรเตอร์ regex =~หากคุณตั้งค่าnocasematchตัวเลือกเชลล์ ตัวอย่างเช่น
s1="hElLo WoRlD"
s2="LO"
shopt -s nocasematch
[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
match
s1="gOoDbYe WoRlD"
[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
no match
[[ XYZ == xyz ]] && echo "match"=>match
สำหรับการค้นหาสตริงที่คำนึงถึงขนาดตัวพิมพ์ของค่าของตัวแปรneedleในค่าของตัวแปรhaystack:
case "$haystack" in
*"$needle"*) echo "present";
*) echo "absent";
esac
สำหรับการค้นหาสตริงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ให้แปลงทั้งสองเป็นกรณีเดียวกัน
uc_needle=$(printf %s "$needle" | tr '[:lower:]' '[:upper:]' ; echo .); uc_needle=${uc_needle%.}
uc_haystack=$(printf %s "$haystack" | tr '[:lower:]' '[:upper:]' ; echo .); uc_haystack=${uc_haystack%.}
case "$uc_haystack" in
*"$uc_needle"*) echo "present";;
*) echo "absent";;
esac
โปรดทราบว่าtrcoreutils ใน GNU ไม่รองรับโลแคลหลายไบต์ (เช่น UTF-8) หากต้องการทำงานกับโลแคลหลายไบต์ให้ใช้ awk แทน หากคุณจะใช้ awk คุณสามารถทำให้การเปรียบเทียบสตริงไม่ใช่แค่การแปลง
if awk 'BEGIN {exit !index(toupper(ARGV[2]), toupper(ARGV[1]))}' "$needle" "$haystack"; then
echo "present"
else
echo "absent"
fi
trจาก BusyBox ไม่สนับสนุนไวยากรณ์; คุณสามารถใช้แทน BusyBox ไม่รองรับภาษาที่ไม่ใช่ ASCII[:CLASS:]tr a-z A-Z
ใน bash (แต่ไม่ใช่ sh), เวอร์ชัน 4.0+, มีไวยากรณ์ในตัวสำหรับการแปลงเคสและไวยากรณ์ที่ง่ายกว่าสำหรับการจับคู่สตริง
if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
echo "present"
else
echo "absent"
esac
printf | trทำให้หัวของฉันหมุนไปรอบ ๆ หากเป็นไปได้ให้คำขอร้องของคุณคำสั่งไปน้อยที่สุด ... v=$(tr '[:lower:]' '[:upper:]' <<<$v)รับวีตัวแปรคุณสามารถบรรลุในสิ่งเดียวกันโดยใช้ สำหรับผู้ที่ไม่เคยเห็นมาก่อน<<<สิ่งสำคัญคือตัวแปร "here here" เช่นการใช้<<EOFเป็นเอกสารที่นี่ อย่าprintfหรือechoถ้าคุณไม่ต้องทำอย่างนั้น
<<<โอเปอเรเตอร์: ksh, bash, zsh แต่ไม่ใช่ sh แบบธรรมดา และมันก็ค่อนข้างใกล้กับท่อจากprintfในแง่ของวิธีการทำงาน: มีจำนวนการโทรไปยังforkและexecve(สมมติว่าprintfมีอยู่แล้วภายในซึ่งเป็นกรณีของเชลล์ที่พบบ่อยที่สุด) ความแตกต่างคือการ<<<สร้างไฟล์ชั่วคราวแทนที่จะใช้ไปป์ <<<สะดวกในการพิมพ์ แต่ไม่ใช่การปรับปรุงประสิทธิภาพ
grep -iอาจจะ?