วิธีใช้ backtick-expansion เพื่อเติมอาร์กิวเมนต์


11

จากความช่วยเหลือ:help backtick-expansion:

On Unix and a few other systems you can also use backticks for the file name
argument, for example:
    :next `find . -name ver\\*.c -print`
    :view `ls -t *.patch  \| head -n1`
The backslashes before the star are required to prevent the shell from
expanding "ver*.c" prior to execution of the find program.  The backslash
before the shell pipe symbol "|" prevents Vim from parsing it as command
termination.

หากฉันพิมพ์คำสั่งจากความช่วยเหลือฉันได้รับข้อผิดพลาด:

:next `find . -name ver\\*.c -print
E79: Cannot expand wildcards  

เหตุใดตัวอย่างจากความช่วยเหลือจึงใช้แบ็กสแลชสองตัวแทนที่จะเป็นหนึ่งและทำไมมันถึงไม่ทำงาน

งานดังต่อไปนี้:

  • หากฉันลบเครื่องหมายแบ็กสแลชหนึ่งในสองตัวที่ป้องกันไม่ให้ดาวขยายโดยเชลล์ก่อนที่findโปรแกรมจะ:

    :next `find . -name ver\*.c -print`
    
  • หากฉันลบแบ็กสแลชทั้งสองและใส่เครื่องหมายคำพูดเดี่ยวรอบ ๆ รูปแบบver*.c:

    :next `find . -name 'ver*.c' -print`
    

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

แต่ความช่วยเหลือให้อีกตัวอย่าง:

:view `ls -t *.patch  \| head -n1`

คำสั่งนี้ทำงานโดยไม่มีการดัดแปลงใด ๆ ไม่จำเป็นต้องมีเครื่องหมายคำพูดเดี่ยว ๆ ไม่จำเป็นต้องใช้แบ็กสแลช
ผมคิดว่าเหตุผลที่ว่าทำไมมันทำงานเป็นเพราะlsคำสั่ง (ตรงกันข้ามกับ-nameข้อโต้แย้งของfindคำสั่ง) *.patchยอมรับข้อโต้แย้งหลายไฟล์และเห็นว่าไม่มีปัญหากับเปลือกขยาย

ทีนี้สมมุติว่าฉันต้องการค้นหาไฟล์ทั้งหมดที่มีนามสกุล.confอยู่ข้างใน/etcโฟลเดอร์และไพพ์เอาท์พุทของfindไปgrepยังเพื่อให้ได้เฉพาะการจับคู่ที่มีสตริงinputเท่านั้น
ในเปลือกจากไดเรกทอรีทำงานใด ๆ ฉันจะพิมพ์:

find /etc -name '*.conf' | grep input

และมันจะทำงาน

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

:next `find /etc -name '*.conf' \| grep input`

และมันใช้งานได้

ตอนนี้ถ้าฉันพิมพ์คำสั่งเดียวกันโดยไม่มีไพพ์และgrep inputฉันได้รับข้อผิดพลาด:

:next `find /etc -name '*.conf'`
E79: Cannot expand wildcards

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

เพื่อลองทำความเข้าใจฉันได้รับคำสั่งที่ง่ายกว่านี้:

find . -name '*.conf'

ค้นหาไฟล์ทั้งหมดที่มีนามสกุล.confในไดเรกทอรีทำงาน คำสั่งทำงานในเชลล์

เพื่อทดสอบเป็นกลุ่มฉันพิมพ์: :next `find . -name '*.conf'`
และใช้งานได้ ในกรณีนี้ dot ย่อมาจากไดเร็กทอรีการทำงานปัจจุบันของฉันตามที่แสดงโดยคำสั่ง Ex :pwdซึ่งเป็นโฮมไดเร็กทอรีของ/home/usernameฉันตั้งแต่ฉันเรียกใช้เซสชัน vim จากมัน

ทำไมมันทำงานเมื่อฉันขอให้ค้นหาในไดเรกทอรีการทำงานปัจจุบันในขณะที่มันไม่ทำงานเมื่อฉันขอให้ค้นหาในโฟลเดอร์โดยพลการเช่น/etc?

ตอนนี้ถ้าฉันเปลี่ยนไดเร็กตอรี่การทำงานของฉันจาก/home/usernameเป็น/etcด้วยคำสั่ง vim Ex :cd /etcและลองคำสั่งเดิมเหมือนเดิมอีกครั้งมันจะผิดพลาดอีกครั้ง:

:next `find . -name '*.conf'`
E79: Cannot expand wildcards

ทำไมการทำงานคำสั่งเดียวกันเมื่อผมอยู่ในโฟลเดอร์ที่บ้านของฉัน แต่ไม่เมื่อผมอยู่ใน/etc?

ฉันแน่ใจว่ามีเหตุผลบางอย่าง แต่ฉันไม่สามารถหาได้

อะไรคือไวยากรณ์ทั่วไปและที่ถูกต้องในการเติมข้อมูล arglist ด้วยคำสั่งเชลล์โดยพลการ (ประกอบด้วยดาว, ไพพ์, ค้นหาในไดเรกทอรีใด ๆ

ฉันใช้ vim รุ่น7.4.942และ zsh เป็นเชลล์เริ่มต้นของฉัน ฉันทดสอบคำสั่งเหล่านี้ด้วยการกำหนดค่าเริ่มต้นขั้นต่ำ ( vim -u NORC -N) จาก bash และ zsh

ฉันจำเป็นต้องกำหนดค่ากลุ่มให้เรียก bash ไม่ใช่ zsh หรือไม่


ฉันสงสัยว่าคุณพยายามเริ่มต้นเป็นกลุ่มด้วยไฟล์ทั้งหมดที่ส่งผ่านเป็นอาร์กิวเมนต์หรือไม่ ฉันหมายถึงบางสิ่งเช่น:vim $(find . -name ver*.c)
Vlad GURDIGA

@VladGURDIGA ฉันได้พยายามเพียงและพวกเขาทั้งหมดทำงานตามที่คาดไว้จากเปลือก: vim $(find . -name ver\*.c -print), vim $(ls -t *.patch | head -n1), vim $(find /etc -name '*.conf' | grep input), vim $(find /etc -name '*.conf'),vim $(find . -name '*.conf')
อว์

@VladGURDIGA แต่ฉันต้องการที่จะรู้วิธีการใส่อาร์กิวเมนต์โดยไม่ต้องออกจากเซสชันปัจจุบันเนื่องจากฉันมักจะมีเพียงหนึ่ง ฉันสามารถย้ายไปมาในเปลือกค้นหากลุ่มของไฟล์และส่งไปยังเซิร์ฟเวอร์ Vim (ด้วยอาร์กิวเมนต์--remoteดู: vi.stackexchange.com/a/5618/4939 ) แต่ฉันอยากรู้วิธีการ ทำโดยตรงจากเซสชั่นปัจจุบัน ถ้ามันเป็นไปไม่ได้มันก็ใช้ได้ แต่หลังจากอ่านความช่วยเหลือแล้วดูเหมือนว่ามันสามารถทำได้ ถ้าเป็นเช่นนั้นฉันอยากจะเข้าใจว่าทำไมกลุ่มเสียงตอบสนองจึงต่างกับคำสั่งที่คล้ายกัน
saginaw

เฮ้ดูเหมือนว่าในคำสั่งตัวอย่างแรกที่คุณพลาด backtick ปิด ;) นอกเหนือจากว่าที่ผมคิดว่าตัวอย่างจากการใช้ความช่วยเหลือทั้งสองเครื่องหมายแทนหนึ่งเพื่อป้องกันไม่ให้การขยายตัวของเปลือกตามที่อธิบายไว้ที่นี่: unix.stackexchange.com/q/104260/23669
Vlad GURDIGA

ในกรณีที่ไม่ได้ทำงานผมคิดว่าบางชื่อตลกออกมาจากคำสั่งที่และนี่อาจจะเป็นเหตุผลที่ว่าทำไมมันทำงานเมื่อประปาผ่านfind /etc -name '*.conf' grep
Vlad GURDIGA

คำตอบ:


6

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

จาก:help `=:

You can have the backticks expanded as a Vim expression, instead of as an
external command, by putting an equal sign right after the first backtick,
e.g.:
    :e `=tempname()`
The expression can contain just about anything, thus this can also be used to
avoid the special meaning of '"', '|', '%' and '#'.  However, 'wildignore'
does apply like to other wildcards.

ดังนั้นแทนที่จะขยายคำสั่งเชลล์โดยตรงเช่นนี้:

:args `shell command`

เราสามารถส่งคำสั่ง shell ไปยังฟังก์ชั่น Vim systemlist()และใช้ expression register =เพื่อขยาย expression ผลลัพธ์เช่นนี้:

:args `=systemlist("shell command")`

หากต้องการบันทึกการกดแป้นบางครั้งฉันได้กำหนดคำสั่ง Ex ต่อไปนี้ใน vimrc ของฉัน ( :PAสำหรับ Populate Arglist):

command! -nargs=1 PA args `=systemlist(<q-args>)`

และทดสอบด้วยคำสั่งเชลล์ต่างๆ:

:PA find . -name ver\*.c -print 2>/dev/null
:PA find . -name 'ver*.c' -print 2>/dev/null
:PA ls -t *.patch  | head -n1
:PA find /etc -name '*.conf' 2>/dev/null | grep input
:PA find /etc -name '*.conf' 2>/dev/null
:PA find . -name '*.conf' 2>/dev/null

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

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