ฉันจะเขียนเชลล์สคริปต์ที่จะทำการจับคู่สตริงย่อยที่ไม่ตรงตามตัวพิมพ์เล็กและใหญ่ของเอาต์พุตคำสั่งได้อย่างไร?
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/sh
ksh
bash
#!
คุณสามารถทำการจับคู่สตริงย่อยแบบไม่ตรงตามตัวอักษรในการ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
โปรดทราบว่าtr
coreutils ใน 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
อาจจะ?