จะใช้ grep output เป็นพา ธ ของ cd ได้อย่างไร?


9

ฉันจะไพพ์grepเอาต์พุตเป็นอาร์กิวเมนต์ของcdคำสั่งได้อย่างไร

ตัวอย่างเช่น:

[root@xxx xxx]# pip install django | grep '/usr.*'  
Requirement already satisfied (use --upgrade to upgrade): django in   /usr/lib64/python2.7/site-packages

นี่/usr/lib64/python2.7/site-packagesคือไฮไลต์และฉันต้องการผ่านสายcdนี้

คำตอบ:


16

ใช้การแทนที่คำสั่ง ของ Bash $()คุณต้อง-oใช้ grep เพื่อเลือกเฉพาะส่วนที่ตรงกัน:

cd "$(pip install django | grep -o '/usr.*')"

โปรดทราบว่าแม้ว่าคุณจะหายไปในกรณีนี้ แต่คุณควรแนบการทดแทนคำสั่งด้วยเครื่องหมายคำพูดคู่เสมอเพื่อให้เชลล์ไม่ดำเนินการแยกคำบนช่องว่าง (ตามพื้นที่เริ่มต้นแท็บและบรรทัดใหม่ขึ้นอยู่กับIFSตัวแปรในกรณีของbash)


9

ทั้งนี้ขึ้นอยู่กับสิ่งที่คุณทำและไม่ทราบล่วงหน้าเกี่ยวกับสิ่งที่pipจะออกคุณอาจตัดสินใจที่จะหาสิ่งอื่นที่ไม่ใช่grep/usr.*

หากคุณรู้ว่าไดเรกทอรีเริ่มต้นด้วย/usr (และปรากฏที่ท้ายบรรทัดผลลัพธ์จากpipนั้นและ/usrจะไม่ปรากฏที่ใดก็ได้ในบรรทัดก่อนชื่อไดเรกทอรี) นั่นคือตัวเลือกที่ดี คำตอบของ heemaylจะบอกคุณว่า

ถ้าเหตุผลที่คุณรู้ว่ามันเริ่มต้นด้วยคือการที่คุณมีเพียงแค่เรียกใช้คำสั่งและทราบไดเรกทอรีที่คุณต้องการที่จะเปลี่ยนแปลงผมขอแนะนำวิธีการแก้ปัญหาที่ง่ายของการใช้คำสั่ง/usr cd /usr/lib64/python2.7/site-packagesนี้เป็นพิมพ์น้อยแม้ว่าคุณจะไม่ได้ใช้ประโยชน์จากเสร็จสิ้นแท็บ

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

หากคุณรู้ว่าชื่อไดเรกทอรีนั้นเป็นสัมบูรณ์ (เช่นเริ่มต้นด้วย a /) และไม่มีชื่อ/ปรากฏบนบรรทัดหน้าชื่อไดเรกทอรีคุณสามารถใช้ regexp เดียวกันกับคำตอบของ heemaylแต่/แทนที่จะเป็น/usr:

cd "$(pip install django | grep -o '/.*')"

ตรงนี้/ตามด้วยศูนย์หรือมากกว่า ( *) ของตัวละครใด ๆ ( .)

หากคุณรู้ว่าชื่อไดเรกทอรีไม่มีช่องว่างแนวนอน (ไม่มีช่องว่างหรือแท็บ) และปรากฏที่ท้ายบรรทัดคุณสามารถใช้:

cd "$(pip install django | grep -oP '[^\h]+$')"

ที่นี่ฉันใช้Perl regexp ( -P) เพราะ\hตัวย่อ (สำหรับ[:blank:]) ทำให้การพิมพ์และอ่านง่ายกว่า regexp แบบขยายที่เทียบเท่า ( -E) สิ่งนี้ตรงกับหนึ่งหรือมากกว่า ( +) ของตัวละครใด ๆ ในคลาสของอักขระ ( [ ]) ที่ไม่ใช่ ( ^) เว้นวรรคหรือแท็บ ( \h)

หากคุณรู้ชื่อไดเรกทอรีจะถูกนำหน้าทันทีโดยinล้อมรอบด้วยช่องว่างแนวนอน (เช่นมีทั้งด้านซ้ายและด้านขวาด้วยช่องว่าง) และนี่เป็นสิ่งเดียวที่เกิดขึ้นinบนบรรทัดคุณสามารถใช้:

cd "$(pip install django | grep -oP '\hin\h+\K.+')"

การใช้งานนี้เป็นศูนย์ที่มีความกว้างในเชิงบวกมองอยู่เบื้องหลังยืนยัน ( \K) เพื่อให้ตรงกับหนึ่งหรือมากกว่าตัวอักษร ( .+) ที่ปรากฏขึ้นหลังจากที่ช่องว่างหรือแท็บ ( \h) inและอีกคนหนึ่งหรือช่องว่างมากขึ้นหรือแท็บ ( \h+) ไม่จริงรวมทั้งinและช่องว่าง ล้อมรอบในการแข่งขัน การยืนยันแบบมองไปรอบ ๆเป็นคุณลักษณะหนึ่งของการแสดงออกปกติของ Perl

รูปแบบจะทำงานได้เช่นกัน แต่เราต้องมองหาสิ่งที่ว่างเปล่ามาก่อนโดยไม่คำนึงว่ามีอยู่กี่ตัว ในทางตรงกันข้ามเราต้องจับคู่ช่องว่างทั้งหมดหลังจากนั้นมิฉะนั้นพวกเขาจะไม่ถูกทิ้งและพวกเขาจะถูกจับคู่เป็นส่วนหนึ่งของชื่อไดเรกทอรี\h+in\h+\K.+inin\K

หากคุณรู้ว่าชื่อไดเรกทอรีนั้นนำหน้าด้วยการปรากฏตัวครั้งสุดท้ายของบรรทัดinตามด้วยช่องว่างแนวนอนคุณสามารถใช้:

set +H
cd "$(pip install django | grep -oP '\hin\h+(?!.*\hin\h.*)\K.*')"
set -H

ที่นั่นการยืนยันการมองด้านหลังเป็นบวกที่มีความกว้างเป็นศูนย์นั้นมีการยืนยันการมองล่วงหน้าในเชิงลบที่มีความกว้างเป็นศูนย์ ( (?! ))

การ!ปรากฏตัวในลักษณะที่ยากต่อการหลบหนีอย่างหรูหรา; วิธีที่ฉันใช้เพื่อป้องกันไม่ให้เกิดการเรียกใช้การขยายประวัติเชลล์ก่อนที่จะถูกส่งไปยังgrepคือการปิดใช้งานการขยายประวัติชั่วคราว ( set +H) ก่อนที่จะเรียกใช้คำสั่งและเปิดใช้งานมันอีกครั้งในset -Hภายหลัง หากคุณกำลังใช้สิ่งนี้ในสคริปต์และสคริปต์ของคุณไม่มีset -Hคุณไม่จำเป็นต้องทำเช่นนี้เนื่องจากการขยายประวัติถูกเปิดใช้งานโดยอัตโนมัติเฉพาะเมื่อเชลล์ทำงานแบบโต้ตอบ

ในที่สุดโปรดทราบว่าไม่มีคำตอบใด ๆ เหล่านี้หรือคำตอบของ heemayl ที่จริงแล้วไพพ์เอาท์พุทของgrepถึงcd(แม้ว่าเอาต์พุตของpipยังคงถูกไพพ์ไปที่grep) แทนที่จะท่อ , เครื่องมือที่เหมาะสมสำหรับงานนี้เป็นคำสั่งเปลี่ยนตัว


แน่นอนถ้าคุณต้องการได้รับเทคนิคเชลล์ใช้ไพพ์ภายในเพื่ออ่านเอาต์พุตคำสั่ง
Random832

@ Random832 ข้อดี: ฉันได้แก้ไขเล็กน้อยในเรื่องนี้ แต่คุณรู้หรือไม่ว่าการใช้ท่อ "ภายใต้ประทุน" ในการทดแทนคำสั่งสามารถพึ่งพาได้หรือไม่? หรือเป็นรายละเอียดการนำไปปฏิบัติที่อาจทำแตกต่างกันในเวอร์ชันทุบตีที่แตกต่างและมีอนาคต (แน่นอนในทางปฏิบัติฉันเข้าใจว่ามันเป็นวิธีที่ดีที่สุดที่จะทำและดังนั้นจึงไม่น่าที่จะนำไปปฏิบัติต่างกัน)
Eliah Kagan

1
ไม่ไม่รับประกันว่าในทางทฤษฎีแล้วเชลล์สามารถใช้ไฟล์ fifo หรือ temp ที่ตั้งชื่อได้แม้ว่าจะไม่มีเหตุผลก็ตาม
Random832

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

1
@muru ใช่มันขยายออกไป ฉันไม่ได้สังเกต แต่ก็พบว่าเมื่อฉันทดสอบมัน !มีไม่ได้อ้างกับ'-quotes เป็น'-quotes ตัวเองที่ยกมา ความซับซ้อนของคำสั่งทำให้ง่ายต่อการคาดการณ์ผลของมันผิด แต่เห็นได้ชัดว่าเนื่องจากคำสั่งของการขยาย ( !เร็วเกินไป)ทำให้การทำงานเหมือนx=foo; echo "'$x'"(-> 'foo') การถอดนอก"-quotes จะทำให้เกิดการ!ที่จะ'-quoted และป้องกันการขยายตัวของประวัติศาสตร์ แต่จากนั้นcd จะล้มเหลวถ้าไดเรกทอรีมีช่องว่างในชื่อ
Eliah Kagan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.