วิธีเรียกใช้ตัวแก้ไข vim และไพพ์เอาต์พุตเพื่อ bash


34

บางครั้งฉันจำเป็นต้องเขียนข้อความจากนั้นส่งข้อความไปยังคำสั่งอื่น เวิร์กโฟลว์ตามปกติของฉันมีลักษณะดังนี้:

vim
# I edit and save my file as file.txt
cat file.txt | pandoc -o file.pdf # pandoc is an example 
rm file.txt

ฉันพบว่ามันยุ่งยากและพยายามเรียนรู้การเขียนสคริปต์ทุบตีฉันต้องการทำให้กระบวนการง่ายขึ้นมากโดยการเขียนคำสั่งที่เปิดไฟเอดิเตอร์และเมื่อเอดิเตอร์ปิดไพพ์เอาต์พุตของเอดิเตอร์เพื่อ stdout quickedit | pandoc -o file.pdfแล้วฉันจะสามารถเรียกใช้คำสั่งเป็น

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

function quickedit {
    filename="$(cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 32)"
    vim $filename
    cat $filename
    rm $filename
}
# The problem:
# => Vim: Warning: Output is not to a terminal

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

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


จากภายในเป็นกลุ่มออกคำสั่ง:w !pandoc -o file.pdf? (หมายเหตุ: ช่องว่างระหว่างwและ!จำเป็น)
John1024

โอเค - เยี่ยมมาก ฉันไม่ทราบว่าคุณสามารถไปป์ vim จากภายในตัวเองได้ สิ่งนี้ทำหน้าที่ตามวัตถุประสงค์ของฉัน แต่สำหรับความรู้ในอนาคตของฉันมันเป็นไปได้หรือไม่ที่จะแก้ปัญหาของฉันอย่างที่ฉันตั้งใจจะแก้ไข?
theideasmith

คุณสามารถโพสต์ฟังก์ชั่นของคุณ? คุณหมายถึงอะไรเมื่อคุณพูดถึงปัญหาที่คุณประสบในไม่ช้า (ย่อหน้าที่สอง) ฉันไม่เข้าใจ
Lucas

5
นอกจากนี้คุณควรใช้mktempมากกว่าสร้างใหม่ในแบบที่ไม่ปลอดภัย
สัญลักษณ์ตัวแทน

ในฐานะผู้ใช้ทุบตีใหม่สิ่งที่อันตรายด้านความปลอดภัยของการฟื้นฟู mktemp คืออะไร?
theideasmith

คำตอบ:


42

vipe เป็นโปรแกรมสำหรับแก้ไขท่อ:

command1 | vipe | command2

คุณได้รับเอดิเตอร์ที่มีเอาต์พุตสมบูรณ์command1และเมื่อคุณออกเนื้อหาจะถูกส่งต่อไปยังcommand2ผ่านไพพ์

command1ในกรณีนี้ไม่มี ดังนั้นคุณสามารถทำได้:

: | vipe | pandoc -o foo.pdf

หรือ:

vipe <&- | pandoc -o foo.pdf

vipeเลือกEDITORและและVISUALตัวแปรเพื่อให้คุณสามารถใช้เพื่อเปิด Vim

หากคุณยังไม่ได้ติดตั้งvipeจะมีให้ในmoreutilsแพ็คเกจ sudo apt-get install moreutilsหรืออะไรก็ตามที่เทียบเท่ากับความอร่อยของคุณคือ


1
สำหรับผู้ใช้ Mac ที่เคยมาที่นี่: moreutilsมีใน Homebrew
vergenzt

สำหรับผู้ใช้ FreeBSD: moreutilsสามารถติดตั้งผ่านpkg (8)ได้
Mateusz Piotrowski

20

คุณสามารถทำได้จากภายใน Vim:

:w !pandoc -o file.pdf

หรือแม้แต่เขียนบัฟเฟอร์ลงในไปป์ไลน์ที่ซับซ้อน:

:w !grep pattern | somecommand > file.txt

จากนั้นคุณสามารถออกจากกลุ่มโดยไม่บันทึก:

:q!

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

set -o vi

viชุดนี้ของคุณเพื่อ keybindings ดังนั้นคุณสามารถแก้ไขคำสั่งของคุณขวาบนบรรทัดคำสั่งที่มีพื้นฐานvikeybindings โดยการกด<Esc>แล้วพิมพ์viคำสั่งเช่นx, cwฯลฯ (คุณจะได้รับกลับมาอยู่ในโหมดแทรกโดยการกดi.)

ดียิ่งขึ้นและเกี่ยวข้องกับคำถามนี้มากขึ้นคุณสามารถเปิด Vim เพื่อสร้างเนื้อหาบรรทัดคำสั่งของคุณได้โดยตรง เพียงพิมพ์<Esc>vและคุณจะได้รับบัฟเฟอร์ Vim ที่ว่างเปล่า เมื่อคุณบันทึกและออกนั่นคือคำสั่งในบรรทัดคำสั่งของคุณและมันจะทำงานทันที นี่คือความยืดหยุ่นมากกว่าการแก้ไขบนบรรทัดคำสั่งโดยตรงเนื่องจากคุณสามารถเขียนมินิสคริปต์ทั้งหมดหากคุณต้องการ


ตัวอย่างเช่นหากคุณต้องการเขียนข้อความที่ซับซ้อนและแปะไปที่ pandoc ทันทีคุณสามารถพิมพ์:

<Esc>v

จากนั้นแก้ไขบัฟเฟอร์ Vim จนกว่าคุณจะมีลักษณะดังนี้:

cat <<EOF | pandoc -o file.pdf
stuff for pandoc
more stuff for pandoc
EOF

จากนั้นบันทึกและออก (พร้อม:x) และทุกสิ่งจะถูกเรียกใช้เป็นคำสั่งเชลล์

มันจะพร้อมใช้งานในประวัติคำสั่งเชลล์ของคุณ


1
หากคุณต้องการเก็บการผูกกุญแจ Emacs ไว้คุณยังคงสามารถใช้ Vim เพื่อแก้ไขบรรทัดคำสั่งได้โดยการตั้งค่าEDITORตัวแปรสภาพแวดล้อมเป็นvimและกดCtrl-Xตามด้วยCtrl-Eในขณะที่แก้ไขบรรทัดคำสั่ง
Anthony G - ความยุติธรรมสำหรับโมนิกา

18

วิ่งไปป์ไลน์

ลอง:

quickedit() (  trap 'rm ~/temp$$' exit; vim ~/temp$$ >/dev/tty; cat ~/temp$$ )

กุญแจสำคัญคือเพื่อให้สามารถใช้งานได้vimตามปกติvimต้องใช้ stdout เป็นเทอร์มินัล เราบรรลุเป้าหมายด้วยการเปลี่ยนเส้นทางที่>/dev/ttyนี่

เพื่อความปลอดภัยฉันวางไฟล์ชั่วคราวไว้ในโฮมไดเร็กตอรี่ของผู้ใช้ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ดูของเกร็กคำถามที่พบบ่อยคำถามที่ 062 สิ่งนี้ทำให้ไม่จำเป็นต้องใช้ชื่อไฟล์คลุมเครือ

ตัวอย่าง:

เมื่อvimเปิดฉันพิมพ์This function succeeded.และบันทึกไฟล์ ผลลัพธ์บนหน้าจอมีลักษณะดังนี้:

$ quickedit | grep succeeded
This function succeeded.

แม้ว่าการส่งออกของquickeditถูกเปลี่ยนเส้นทางไปท่อยังคงทำงานตามปกติเพราะเราได้ให้มันเข้าถึงโดยตรงไปยังvim/dev/tty

เรียกใช้โปรแกรมจากภายในกลุ่ม

ดังที่ฉันได้กล่าวถึงในข้อคิดเห็นข้อคิดเห็นเป็นกลุ่มสามารถไพพ์ไฟล์ไปยังคำสั่ง ยกตัวอย่างเช่นจากภายในเป็นกลุ่มออกคำสั่ง:w !pandoc -o file.pdf(หมายเหตุ: ช่องว่างระหว่าง w และ! เป็นสิ่งจำเป็น)


2
คำตอบที่ดี หนึ่งนี้ตรงกับคำถามของผู้ใช้และนำเสนอโซลูชั่นที่รวดเร็วและสง่างาม: เปลี่ยนเป็นกลุ่มเป็น / dev / tty! ! ง่าย
Mike S

ฉันใช้ Zsh; trap '...' exitล้มเหลว แต่trap '...' EXITดูเหมือนว่าจะทำงาน ผมไม่ทราบว่ามากเกี่ยวกับการวางกับดัก mktmp [--suffix=...]แต่วิธีการทั่วไปของฉันสำหรับไฟล์ชั่วคราวคือการใช้งาน นอกจากนี้ให้vim <outfile> -c '...' >/dev/ttyรันตามปกติจนกระทั่งไฟล์ถูกโหลดจากนั้นเรียกใช้งานเชนคำสั่งที่กำหนดรวมถึง:wqหากคุณต้องการข้ามเฟสการแก้ไข ฉันยังใช้และพบว่าset | grep -a EXIT signals=(EXIT ... DEBUG)
John P

5

ตรวจสอบให้แน่ใจว่าvimได้ตั้งค่าเป็นตัวแก้ไขเริ่มต้นของคุณ (เช่นexport EDITOR=vimใน.bash_profileหรือ.bashrcจากนั้นคุณสามารถพิมพ์Ctrl- Xตามด้วยCtrl- Eเพื่อเปิดบรรทัดคำสั่งปัจจุบันของคุณในตัวแก้ไขที่กำหนดค่า (เช่นvim) ทำการแก้ไขบันทึกและ ออกและคำสั่งจะถูกดำเนินการราวกับว่าคุณได้พิมพ์มันในบรรทัดคำสั่งรวมถึงท่อและไม่ชอบ

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