เหตุใด [az] เครื่องหมายดอกจันจึงจับคู่หมายเลข


13

ฉันมี 3 ไดเรกทอรีที่เส้นทางปัจจุบัน

$ls
a_0db_data  a_clean_0db_data  a_clean_data
$ls a_*_data
a_0db_data:

a_clean_0db_data:

a_clean_data:

$ls a_[a-z]*_data
a_clean_0db_data:

a_clean_data:

ผมคาดว่าคำสั่ง ls a_clean_dataสุดท้ายคำสั่งเพื่อให้ตรงเท่านั้น ทำไมถึงยังตรงกับที่มี0?

bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)

2
ดูคำถามนี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับความแตกต่างระหว่างนิพจน์ทั่วไปและ glob
terdon

4
ดังนั้นความจริงที่ว่าการa_*_dataจับคู่ใด ๆ ของไฟล์นี้ไม่ได้ทำให้คุณแปลกใจ?
คธูลู

@Cululhu คุณได้รับฉัน!
user13107

คำตอบ:


29

[a-z]ส่วนหนึ่งไม่ได้เป็นสิ่งที่ตรงกับหมายเลขนั้น *มันเป็น คุณอาจจะทำให้เกิดความสับสนเปลือกglobbingและการแสดงออกปกติ

เครื่องมือเช่นgrepยอมรับการยอมรับรสชาติต่าง ๆ ของ regexes ( พื้นฐานโดยค่าเริ่มต้น-Eสำหรับการขยาย-PสำหรับPerl regex )

เช่น ( -vย้อนกลับการแข่งขัน)

$ ls a_[a-z]*_data | grep -v "[0-9]"
a_clean_data

หากคุณต้องการใช้ bash regex นี่คือตัวอย่างวิธีการทดสอบว่าตัวแปร$refเป็นจำนวนเต็มหรือไม่:

re='^[0-9]+$'
if ! [[ $ref =~ $re ]] ; then
  echo "error"
fi

วิธีการใช้ bash regex นั้น? (ดูtldp.org/LDP/Bash-Beginners-Guide/html/sect_04_01.html )
user13107


21

ดังนั้นปัญหาคือทำไมไม่a_[a-z]*_dataตรงa_clean_0db_data?

สิ่งนี้สามารถแบ่งออกเป็นสี่ส่วน:

  • a_ตรงกับจุดเริ่มต้นของa_clean_0db_dataออกจากclean_0db_dataการจับคู่

  • [a-z]จับคู่อักขระใด ๆ ในช่วงa-z(เช่นc) ออกจากlean_0db_dataการจับคู่

  • * ตรงกับจำนวนอักขระใด ๆ เช่น lean_0db

  • _data ตรงกับส่วนท้าย _data

ในนิพจน์ทั่วไป[a-z]*จะหมายถึงจำนวนอักขระใด ๆ (รวมถึงศูนย์) ในช่วง a .. zแต่คุณกำลังเผชิญกับการวนรอบของเชลล์ไม่ใช่การแสดงผลปกติ

หากคุณต้องการนิพจน์ทั่วไปการfindใช้งานสองสามครั้งจะมีภาค-regexแสดงดังนี้

find . -maxdepth 1 -regex "^.*/a_[a-z]*_data$"

นี่-maxdepthเป็นเพียงที่นี่เพื่อ จำกัด การค้นหาผลลัพธ์ไปยังโฟลเดอร์ที่คุณอยู่นิพจน์ปกติตรงกับชื่อไฟล์ทั้งหมดดังนั้นฉันได้เพิ่ม a ^.*/เพื่อให้ตรงกับเส้นทางส่วน


11

*ในรูปแบบเชลล์ตรงกับ 0 หรือมากกว่าตัวละคร ก็เพื่อไม่ให้สับสนกับ*ผู้ประกอบการแสดงออกปกติที่หมายถึง0 หรือมากกว่าของอะตอมก่อน

ไม่เท่ากับ regexp *ในรูปแบบเชลล์พื้นฐาน อย่างไรก็ตามเชลล์ต่าง ๆ มีส่วนขยายสำหรับสิ่งนั้น

  • kshมี*(something):

    ls a_*([a-z])_data
  • คุณสามารถมีเดียวกันในbashด้วยshopt -s extglobหรือzshกับsetopt kshglob:

    shopt -s extglob
    ls a_*([a-z])_data
  • ในzshที่มีextendedglobการเปิดใช้งาน#เทียบเท่ากับ regexp *:

    setopt extendedglob
    ls a_[a-z]#_data
  • ในเวอร์ชันล่าสุดของksh93คุณยังสามารถใช้นิพจน์ทั่วไปเป็นกลุ่ม ที่นี่ด้วยการแสดงออกปกติขยาย :

    ls ~(E:a_[a-z]*_data)

โปรดทราบว่า[a-z]ตรงกับสิ่งต่าง ๆ ขึ้นอยู่กับตำแหน่งที่ตั้งปัจจุบัน มันมักจะตรงกับเพียง 26 aไปยังzตัวอักษรที่ไม่ใช่สำเนียงภาษาละตินในCสถานที่เกิดเหตุ ในสถานที่อื่น ๆ โดยทั่วไปจะจับคู่มากกว่าและไม่สมเหตุสมผลเสมอไป [[:alpha:]]เพื่อให้ตรงกับตัวอักษรในภาษาของคุณคุณอาจจะชอบ


คุณช่วยยกตัวอย่างการ[a-z]จับคู่มากกว่าที่ตัวอักษร 26 ตัวจับคู่ในโลแคล C หรือไม่? สิ่งที่ฉันจำได้เมื่อครั้งล่าสุดที่ฉันดูสิ่งนี้การเข้ารหัสทั้งหมดที่ใช้จริงในชุด Unix มี ISO-646 เป็นฐาน (จากนั้นรหัส 128 ส่วนบนที่ใช้แตกต่างกันโดยตรงสำหรับอักขระในการเข้ารหัสเช่น ISO-8859-X การเข้ารหัสเช่น UTF-8 หรือตระกูล EUC) แม้แต่ AIX ก็ไม่มีตำแหน่ง EBCDIC (อย่างน้อยก็มีให้ฉัน) ฉันจำได้ว่าพยายามค้นหาว่ามาตรฐาน POSIX / UNIX เรียกร้องหรือไม่ แต่ฉันจำผลลัพธ์ไม่ได้
AProgrammer

1
@AProgrammer ที่เป็นอิสระจากการเข้ารหัสที่ขึ้นอยู่กับการเรียงลำดับ (LC_COLLATE) [a-z]โดยทั่วไปจะรวมéหรือí(แต่ไม่จำเป็นź) ในตำแหน่งที่ตั้งที่ชุดอักขระมีให้ไม่ว่า codepoint ในการเข้ารหัสนั้นอยู่ระหว่าง a และ z หรือไม่ เฉพาะโลแคล C รับประกันการเรียงลำดับตามค่า codepoint ดูคำตอบอื่น ๆ นี้สำหรับรายละเอียดเพิ่มเติม
Stéphane Chazelas

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