การค้นหาสตริงย่อยแบบคำนึงถึงขนาดตัวพิมพ์ในเชลล์สคริปต์ [ปิด]


22

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


grep -iอาจจะ?
Ramesh

ฉันจะใส่สิ่งนั้นไว้ในสคริปต์ของฉันได้อย่างไร ฉันขอโทษถ้านี่เป็นคำถามสามเณร ฉันเพิ่งเริ่มเรียน Linux เพราะฉันต้องการมันสำหรับการฝึกงาน ขอบคุณ!
Miguel Roque

1
สิ่งที่คุณถามเกี่ยวกับคือการเขียนสคริปต์เชลล์ - "linux" ไม่ใช่ภาษาโปรแกรมเป็นเคอร์เนลระบบปฏิบัติการ เปลือกใช้กันมากที่สุดกับลินุกซ์bashซึ่งเป็น superset ของมาตรฐานยูนิกซ์ shคุณอาจเริ่มด้วยการดูหนึ่งในนี้: | 1 | | 2 | - เพียงเพื่อให้ได้มาซึ่งบริบทที่แท้จริง
goldilocks

1
ตอนนี้คำถามนี้ค่อนข้างชัดเจนและตรงกับหลักเกณฑ์ในศูนย์ช่วยเหลือ โปรดเปิดให้เป็นประโยชน์ต่อผู้อื่นได้หรือไม่?
BobDoolittle

2
ฉันไม่เห็นเหตุผลที่คำถามนี้ไม่ชัดเจน ฉันควรเพิ่มอะไรเพื่อให้ชัดเจน?
Miguel Roque

คำตอบ:


11

ครั้งแรกที่นี่เป็นตัวอย่างสคริปต์ง่ายๆที่ไม่สนใจกรณีและปัญหา:

#!/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 ]


ฉันไม่เข้าใจว่าทำไม Gilles รู้สึกว่าจำเป็นต้องเปลี่ยนรหัสที่ฉันมีส่วน เขาไม่ได้ทำลายอะไรเลย แต่มันก็ใช้ได้ดี คุณไม่จำเป็นต้องใช้เครื่องหมายคำพูดคู่ในตัวอย่างนี้ - มันมีความสำคัญหากเอาต์พุตมีช่องว่าง และ == ทำงานได้ดีเช่นเดียวกับ = เพราะ sh เป็นจริงทุบตีบน Linux Bourne Shell ดั้งเดิมหายไปนานแล้ว ณ เวลานี้ ฉันไม่คิดว่าแม้แต่ Solaris จะจัดส่งอีกต่อไป ในขณะที่ไม่จำเป็นในตัวอย่างนี้ฉันยอมรับว่าการเสนอราคาซ้ำซ้อนอาจเป็นแนวปฏิบัติที่ดีที่สุด แต่ในความคิดของฉันคือ '==' เพื่อแยกการกำหนดและการเปรียบเทียบออกจากกันอย่างชัดเจน
BobDoolittle

รอก่อนใครจะแก้ไขโพสต์ได้บ้าง ผมไม่ทราบว่า.
Miguel Roque

มีชื่อเสียงเพียงพอ ฉันหวังว่าคนที่มีชื่อเสียงจะคิดสองครั้งก่อนที่จะทำการแก้ไขโดยไม่จำเป็นโดยเฉพาะอย่างยิ่งโค้ดในฟอรัมนี้ unix.stackexchange.com/help/privileges
BobDoolittle

@BobDoolittle อาจมีบางกรณีที่สร้างความแตกต่าง แต่ไม่ใช่กับการตั้งค่าของคุณ - เป็นการดีที่จะรู้

2
โปรดสังเกตว่าในทางปฏิบัติมันไม่ได้เกี่ยวกับเชลล์เป้าหมายเท่านั้น ==ไม่ใช่ POSIX shไม่ได้bashอยู่บนระบบที่ใช้ Linux ทั้งหมด ==ไม่ได้รับการสนับสนุนจากash(ขึ้นอยู่กับที่shของ BSDs จำนวนมากและสัญญาซื้อขายล่วงหน้า Debian อย่างน้อยจะขึ้น) หรือและความต้องการยกมาในposh มีจุดวกกลับไม่ได้zsh เป็นคำสั่งสำหรับการทดสอบ ไม่จำเป็นต้องแยกแยะระหว่างการมอบหมายและการเปรียบเทียบที่นี่ นั่นคือความแตกต่างในVS การใช้สคริปต์ที่ขึ้นต้นด้วยผิด หากคุณสมมติหรือไวยากรณ์ให้ปรับปรุงตามนั้น =[(( a == b ))(( a = b))==#! /bin/shkshbash#!
Stéphane Chazelas

49

คุณสามารถทำการจับคู่สตริงย่อยแบบไม่ตรงตามตัวอักษรในการ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

6
ฮ่า ๆ! คะแนนสำหรับความรู้เปลือกปิดบัง
BobDoolittle

2
ตัวเลือกนี้จะมีผลกับตัวดำเนินการจับคู่แบบง่ายด้วย [[ XYZ == xyz ]] && echo "match"=>match
itsadok

7

สำหรับการค้นหาสตริงที่คำนึงถึงขนาดตัวพิมพ์ของค่าของตัวแปร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ถ้าคุณไม่ต้องทำอย่างนั้น
จะ

@ Will จะใช้งานได้ในเชลล์ที่มี<<<โอเปอเรเตอร์: ksh, bash, zsh แต่ไม่ใช่ sh แบบธรรมดา และมันก็ค่อนข้างใกล้กับท่อจากprintfในแง่ของวิธีการทำงาน: มีจำนวนการโทรไปยังforkและexecve(สมมติว่าprintfมีอยู่แล้วภายในซึ่งเป็นกรณีของเชลล์ที่พบบ่อยที่สุด) ความแตกต่างคือการ<<<สร้างไฟล์ชั่วคราวแทนที่จะใช้ไปป์ <<<สะดวกในการพิมพ์ แต่ไม่ใช่การปรับปรุงประสิทธิภาพ
Gilles 'ดังนั้นหยุดความชั่วร้าย'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.