ด้วย Terminal: การใช้ Regular Expressions II: การเปลี่ยน

ในบทความก่อนหน้านี้ผมได้อธิบายในระดับพื้นฐานเกี่ยวกับวิธีการทำงานของอักขระพิเศษที่ใช้กันทั่วไปในนิพจน์ปกติ (regular expression) แต่ละตัว ด้วยนิพจน์ปกติเหล่านี้ เราสามารถทำการค้นหาที่ซับซ้อนในไฟล์ข้อความหรือในผลลัพธ์ของคำสั่งอื่นๆ ได้ ในบทความนี้ ผมจะอธิบายวิธีการใช้คำสั่ง `sed` เพื่อค้นหาและแทนที่ข้อความในวิธีที่มีประสิทธิภาพมากกว่าการแทนที่ข้อความหนึ่งด้วยข้อความอื่นเพียงอย่างเดียว

เพิ่มเติมเล็กน้อยเกี่ยวกับคำสั่ง grep

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

การรวมนิพจน์ทั่วไป

อักขระพิเศษหลายตัวที่ฉันได้พูดถึงในบทความก่อนหน้านี้สามารถรวมกันได้ไม่เพียง แต่กับอักขระอื่น ๆ เท่านั้น แต่ยังมีนิพจน์ทั่วไปทั้งหมดด้วย วิธีทำคือใช้วงเล็บเพื่อสร้างนิพจน์ย่อย ลองดูตัวอย่างนี้ เริ่มต้นด้วยการดาวน์โหลดข้อความที่เราสามารถใช้ในการทดสอบ มันคือรายการของวลี เพื่อที่เราจะใช้คำสั่งต่อไปนี้:

curl http://artigoo.com/lista-de-frases-comparativas-comicas 2>/dev/null | sed -n 's/.*\(.*\.\)<\/p>/\1/gp' > frases

 สิ่งนี้จะทำให้คุณอยู่ในไดเร็กทอรีที่คุณเปิดไฟล์ชื่อ "วลี" สามารถเปิดดูหัวเราะได้นิดหน่อย

ทีนี้สมมติว่าเราต้องการหาวลีที่มี 6 คำ ความยากอยู่ที่การสร้างนิพจน์ทั่วไปที่ตรงกับแต่ละคำ คำคือลำดับของตัวอักษรไม่ว่าจะเป็นตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็กซึ่งจะเป็นอย่างไร '[a-zA-Z]+'แต่คุณต้องระบุด้วยว่าตัวอักษรเหล่านี้จะต้องคั่นด้วยอักขระอื่นที่ไม่ใช่ตัวอักษรนั่นคือมันจะคล้าย ๆ '[a-zA-Z]+[^a-zA-Z]+'. จำไว้ว่า: "^" เป็นอักขระตัวแรกในวงเล็บแสดงว่าเราต้องการจับคู่กับอักขระที่ไม่อยู่ในช่วงและ "+" หมายถึงอักขระ 1 ตัวขึ้นไป

เรามีนิพจน์ทั่วไปที่สามารถจับคู่คำได้แล้ว ในการจับคู่กับ 6 จะต้องทำซ้ำ 6 ครั้ง เพราะเราใช้กุญแจ แต่มันไม่มีประโยชน์ที่จะใส่ '[a-zA-Z]+[^a-zA-Z]+{6}'เนื่องจาก 6 จะทำซ้ำส่วนสุดท้ายของนิพจน์ทั่วไปและสิ่งที่เราต้องการคือทำซ้ำทั้งหมดดังนั้นสิ่งที่เราต้องใส่คือ: '([a-zA-Z]+[^a-zA-Z]+){6}'. ด้วยวงเล็บเราสร้างนิพจน์ย่อยและด้วยวงเล็บปีกกาเราทำซ้ำ 6 ครั้ง ตอนนี้คุณต้องเพิ่ม "^" ด้านหน้าและ "$" ที่ด้านหลังเพื่อให้ตรงกับบรรทัดทั้งหมด คำสั่งมีดังนี้:

grep -E '^([a-zA-Z]+[^a-zA-Z]+){6}$' frases

และผลลัพธ์คือสิ่งที่เราต้องการ:

มันร้องยิ่งกว่า Macarena คุณเสร็จสิ้นมากกว่า Luis Aguilé คุณมีวัฒนธรรมน้อยกว่าหิน คุณรู้ภาษามากกว่าCañita Brava เขามีริ้วรอยมากกว่า Tutan Khamón คุณรู้น้อยกว่าแรมโบ้เรื่องการเลี้ยงลูก

สังเกตว่าเราใส่พารามิเตอร์ -E เพราะเราต้องการใช้นิพจน์ทั่วไปแบบขยายเพื่อให้ "+" ทำงาน ถ้าเราใช้พื้นฐานเราจะต้องหนีจากวงเล็บและเครื่องมือจัดฟัน

การอ้างอิงย้อนกลับหรือการอ้างอิงย้อนกลับ

หากคุณติดตั้งเครื่องตรวจตัวสะกดไว้คุณอาจมีรายการคำใน /usr/share/dict/words. หากไม่เป็นเช่นนั้นคุณสามารถติดตั้งในซุ้มด้วย:

sudo pacman -S words

หรือในเดเบียนด้วย:

sudo aptitude install dictionaries-common

หากคุณต้องการคุณสามารถดูไฟล์เพื่อดูว่ามีคำอะไรบ้าง จริงๆแล้วมันเป็นลิงค์ไปยังไฟล์ word ของภาษาที่คุณอยู่ใน distro คุณสามารถติดตั้งไฟล์ word หลายไฟล์พร้อมกันได้

เราจะใช้ไฟล์นั้น ปรากฎว่าเราอยากรู้มากที่จะรู้จักตัวอักษร palindromes ทั้งเจ็ดที่นั่น สำหรับผู้ที่ไม่ทราบ: Palindrome เป็นคำคาปิคูกล่าวคือสามารถอ่านจากซ้ายไปขวาและจากขวาไปซ้าย ลองใช้คำสั่งต่อไปนี้:

grep '^\(.\)\(.\)\(.\).\3\2\1$' /usr/share/dict/words

มันดูแปลก ๆ ใช่มั้ย? หากเราลองใช้ผลลัพธ์จะขึ้นอยู่กับภาษาของ distro ของคุณและคำที่อยู่ในรายการของคุณ แต่ในกรณีของฉันด้วยภาษาสเปนผลลัพธ์ที่ได้คือ:

aniline aniline กลิ้ง

มาดูกันว่านิพจน์ทั่วไปทำงานอย่างไร

นอกเหนือจาก "^" และ "$" ซึ่งเรารู้อยู่แล้วว่ามีไว้เพื่ออะไรสิ่งแรกที่เราเห็นทางด้านซ้ายคือกลุ่มของจุดสามกลุ่มที่อยู่ในวงเล็บ อย่าสับสนกับแถบที่อยู่หน้าวงเล็บแต่ละอัน พวกเขาต้องหนีจากวงเล็บเพราะเราใช้นิพจน์ทั่วไปพื้นฐาน แต่ไม่มีความหมายอื่น สิ่งสำคัญคือเรากำลังขออักขระสามตัวที่มีจุด แต่แต่ละจุดนั้นอยู่ในวงเล็บ นี่คือการบันทึกอักขระที่ตรงกับจุดเหล่านั้นเพื่อให้สามารถอ้างอิงได้อีกครั้งจากนิพจน์ทั่วไป นี่คือการใช้วงเล็บอื่นที่จะมีประโยชน์ในภายหลังสำหรับการเปลี่ยน

นี่คือที่ที่ตัวเลขสามตัวด้านล่างมาพร้อมกับเครื่องหมายทับหน้าพวกเขา ในกรณีนี้แถบมีความสำคัญ ใช้เพื่อระบุว่าตัวเลขด้านล่างนี้เป็นการอ้างอิงย้อนกลับและอ้างถึงหนึ่งในวงเล็บก่อนหน้านี้ ตัวอย่างเช่น \ 1 หมายถึงวงเล็บแรก, \ 2 ถึงที่สองและอื่น ๆ

กล่าวอีกนัยหนึ่งด้วยนิพจน์ทั่วไปที่เราใส่ไว้สิ่งที่เรากำลังมองหาคือคำทั้งหมดที่ขึ้นต้นด้วยตัวอักษรสี่ตัวใด ๆ จากนั้นมีตัวอักษรที่เหมือนกับตัวที่สามอีกตัวที่เหมือนกับตัวที่สองและอีกตัวที่เหมือนกันกับ อันดับแรก. ผลลัพธ์คือ palindromes ตัวอักษรเจ็ดตัวที่อยู่ในรายการคำ ตามที่เราต้องการ

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

นิพจน์การแทนที่: คำสั่ง sed

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

sed [-r] 's/REGEX/REPL/g' FICHERO

หรือยัง:

COMANDO | sed [-r] 's/REGEX/REPL/g'

โดย REGEX จะเป็นนิพจน์ทั่วไปในการค้นหาและ REPL แทนที่ โปรดทราบว่าคำสั่งนี้ไม่ได้แทนที่อะไรในไฟล์ที่เราระบุ แต่สิ่งที่แสดงให้เราเห็นผลลัพธ์ของการแทนที่ในเทอร์มินัลดังนั้นอย่ากลัวกับคำสั่งที่ฉันจะใส่ต่อไป ไม่มีใครจะแก้ไขไฟล์ใด ๆ ในระบบของคุณ

เริ่มจากตัวอย่างง่ายๆ เราทุกคนมีไฟล์คอนฟิกูเรชันต่างๆในไดเร็กทอรี / etc ซึ่งมักจะมีความคิดเห็นขึ้นต้นด้วย "#" สมมติว่าเราต้องการดูไฟล์เหล่านี้โดยไม่มีความคิดเห็น ตัวอย่างเช่นผมจะใช้ fstab คุณสามารถลองกับสิ่งที่คุณต้องการ

sed 's/#.*//g' /etc/fstab

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

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

ตอนนี้เราจะทำตรงกันข้าม สมมติว่าสิ่งที่เราต้องการคือแสดงความคิดเห็นทุกบรรทัดของไฟล์ ลองทำดังนี้

sed 's/^/# /g' /etc/fstab

คุณจะเห็นว่าในผลลัพธ์ของคำสั่งทุกบรรทัดเริ่มต้นด้วยเครื่องหมายแฮชและช่องว่าง สิ่งที่เราทำคือแทนที่จุดเริ่มต้นของบรรทัดด้วย«# «. นี่เป็นตัวอย่างที่ค่อนข้างง่ายที่ข้อความที่จะถูกแทนที่จะเหมือนกันเสมอ แต่ตอนนี้เราจะทำให้มันซับซ้อนขึ้นอีกเล็กน้อย

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

sed 's/\([A-Z]\)/(\1)/g' frases

สิ่งที่เรามีอยู่ที่นี่คือ backreference ในนิพจน์การแทนที่ที่อ้างถึงวงเล็บในนิพจน์การค้นหา วงเล็บในนิพจน์การแทนที่เป็นวงเล็บปกติ ในนิพจน์แทนที่พวกเขาไม่มีความหมายพิเศษพวกเขาถูกใส่ตามที่เป็นอยู่ ผลลัพธ์คือตัวพิมพ์ใหญ่ทั้งหมดจะถูกแทนที่ด้วยตัวอักษรเดียวกันไม่ว่าจะเป็นอะไรก็ตามโดยมีวงเล็บล้อมรอบ

มีอักขระอื่นที่สามารถใช้ในนิพจน์แทนที่ได้เช่นกันคือ "&" และจะถูกแทนที่ด้วยข้อความทั้งหมดที่ตรงกับนิพจน์การค้นหา ตัวอย่างนี้อาจเป็นการใส่วลีทั้งหมดในไฟล์ในเครื่องหมายคำพูด สิ่งนี้สามารถทำได้ด้วยคำสั่งนี้:

sed 's/.*/"&"/g' frases

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

คำสั่งที่มีประโยชน์บางคำสั่งพร้อมนิพจน์ทั่วไป

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

  • แสดงส่วนต่างๆของ man page:

man bash | grep '^[A-Z][A-Z ]*$'

แน่นอนคุณสามารถเปลี่ยนคำสั่ง bash เป็นอะไรก็ได้ที่คุณต้องการ จากนั้นคุณสามารถไปที่ส่วนที่คุณสนใจได้โดยตรงซึ่งเป็นนิพจน์ทั่วไป คุณกด« / »เพื่อเริ่มค้นหาและเขียน«^ALIASES$»หากต้องการไปที่ส่วน ALIASES ตัวอย่างเช่น ฉันคิดว่านี่เป็นการใช้ครั้งแรกที่ฉันเริ่มสร้างนิพจน์ทั่วไปเมื่อสองสามปีก่อน การเลื่อนดูบางหน้าของคู่มือแทบจะเป็นไปไม่ได้เลยหากไม่มีเคล็ดลับเช่นนี้

  • แสดงชื่อของผู้ใช้เครื่องทั้งหมดรวมถึงชื่อพิเศษ:

sed 's/\([^:]*\).*/\1/' /etc/passwd

  • แสดงชื่อผู้ใช้ แต่เฉพาะชื่อที่มีเชลล์:

grep -vE '(/false|/nologin)$' /etc/passwd | sed 's/\([^:]*\).*/\1/g'

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

  • ใส่ลูกน้ำหน้าสามหลักสุดท้ายของตัวเลขทั้งหมดในไฟล์ Numbers:

sed 's/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g' numbers

ใช้งานได้กับตัวเลขไม่เกิน 6 หลัก แต่สามารถเรียกได้มากกว่าหนึ่งครั้งเพื่อวางคั่นในกลุ่มสามหลักอื่น ๆ

  •  แยกที่อยู่อีเมลทั้งหมดออกจากไฟล์:

grep -E '\<[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}\>' FICHERO

  • แยกวันเดือนและปีของวันที่ทั้งหมดที่ปรากฏในไฟล์:

sed -r 's/([0-9]{2})[/-]([0-9]{2})[/-]([0-9]{4})/Día: \1, Mes: \2, Año: \3/g' FICHERO

  • ค้นหา IP ในพื้นที่ของเรา:

/sbin/ifconfig | grep 'inet .*broadcast' | sed -r 's/[^0-9]*(([0-9]+\.){3}[0-9]+).*/\1/g'

สิ่งนี้สามารถทำได้ด้วยคำสั่ง sed เดียว แต่ฉันควรแยกมันออกเป็น grep และ sed เพื่อความเรียบง่าย

ที่อยู่ที่เป็นประโยชน์

นี่คือที่อยู่บางส่วนที่อาจเป็นประโยชน์เกี่ยวกับนิพจน์ทั่วไป:

  • ไลบรารีนิพจน์ทั่วไป: นี่คือไลบรารีนิพจน์ทั่วไปที่คุณสามารถค้นหานิพจน์ทั่วไปที่เกี่ยวข้องกับหัวข้อที่คุณสนใจ เพื่อค้นหาที่อยู่เว็บ ID หรืออะไรก็ตาม
  • RegExr: ตัวตรวจสอบนิพจน์ทั่วไปออนไลน์ ช่วยให้คุณสามารถป้อนข้อความและใช้นิพจน์ทั่วไปในการค้นหาหรือแทนที่ ให้ข้อมูลเกี่ยวกับนิพจน์ทั่วไปและคุณมีทางเลือกในการเปลี่ยนแปลงพฤติกรรม
  • เครื่องทดสอบนิพจน์ทั่วไป: เป็นส่วนเสริมสำหรับ firefox ที่ให้คุณตรวจสอบนิพจน์ทั่วไปจากเบราว์เซอร์

ข้อสรุป

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

เฮ้! …เฮ้! …ตื่น! …คุณกำลังทำอะไรในขณะที่นอนหลับ?

Fuentes

แนวคิดและตัวอย่างบางส่วนสำหรับนิพจน์ทั่วไปในบทความนี้ฉันได้นำมาจากที่นี่:


เพิ่มเป็นแหล่งข้อมูลที่ต้องการใน Google