เทอร์มินัล borked หลังจากเรียกใช้ Vim ด้วย xargs


30

บางครั้งฉันพยายามเรียกใช้ Vim โดยใช้วิธีxargsนี้:

find . -name '*.java' | xargs vim

…งานประเภทใด:

  1. เมื่อ Vim เปิดตัวฉันจะเห็นแฟลชคำเตือนต่อไปนี้สั้น ๆ :

    Vim: Warning: Input is not from a terminal
    
  2. การแก้ไขการทำงาน - :filesระบุ.javaไฟล์ทั้งหมดอย่างถูกต้องตามที่คาดไว้
  3. ฉันสามารถบันทึกและออกจาก

อย่างไรก็ตามหลังจากออกจาก Vim เทอร์มินัลของฉันถูก borked:

  • สิ่งที่ฉันพิมพ์ที่ shell prompt ไม่ได้สะท้อน
  • การขึ้นบรรทัดใหม่จะไม่ปรากฏเลยและบางครั้งการป้อนบรรทัดก็จะปรากฏขึ้น

สิ่งนี้จะดำเนินต่อไปจนกว่าฉันจะออกreset(1)คำสั่งเพื่อกำหนดค่าเริ่มต้นใหม่ให้กับเทอร์มินัล

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

vim $(find . -name '*.java')ฉันรู้หนึ่งวิธีแก้ปัญหาคือ การแก้ไขปัญหาอื่น ๆ จะได้รับการต้อนรับแม้ว่าจะไม่ใช่คำถามหลักของฉัน


ฉันอยากให้คุณเติมคำถามนี้ให้มากที่สุดเท่าที่จะเป็นไปได้ แต่ ... คำถามนั้นได้รับการตอบแล้วหลายสิบครั้งในช่วงหลายปีที่ผ่านมาใน SO / SU และที่อื่น ๆ : xargsใช้ตัวอย่างstdinที่ Vim และ break ไม่สามารถใช้ ทุกอย่างในภายหลัง
romainl

1
@ ฉีดฉันไม่ได้ใช้งานเว็บไซต์เหล่านั้นและฉันไม่เคยเห็นมันถามมี - ซื่อสัตย์
200_success

ที่เกี่ยวข้อง: superuser.com/questions/336016/… - บางทีใครบางคนสามารถย่อคำตอบที่ดีที่สุดสำหรับคำตอบที่ดี
muru

2
คำถามยอดเยี่ยม - สิ่งนี้เกิดขึ้นกับฉันหลายครั้ง นอกจากนี้ฉันไม่ได้ใช้ไซต์ SO อื่น ๆ - หากเกี่ยวข้องกับเสียงเรียกเข้าฉันต้องการค้นหาที่นี่
craigp

คำตอบ:


21

สิ่งนี้เกิดขึ้นเมื่อมีการเรียกใช้ vim และเชื่อมต่อกับเอาต์พุตของไพพ์ไลน์ก่อนหน้าแทนที่จะเป็นเทอร์มินัลและได้รับอินพุตที่ไม่คาดคิดที่แตกต่างกัน (เช่น NUL) สิ่งเดียวกันจะเกิดขึ้นเมื่อคุณเรียกใช้: vim < /dev/nullดังนั้นresetคำสั่งในกรณีนี้จะช่วยได้ นี้จะอธิบายได้ดีโดยgrawity ที่ superuser

หากคุณใช้findเพื่อส่งชื่อไฟล์เพื่อแก้ไขคุณไม่จำเป็นต้องxargsใช้-execตัวอย่างเช่น:

find . -name '*.java' -exec vim {} +

หากคุณต้องการใช้xargsบน Unix / macOS คุณควรใช้-oพารามิเตอร์เช่น:

find . -name '*.java' | xargs -o vim

-oเปิด stdin อีกครั้งเป็น / dev / tty ในกระบวนการ child ก่อนดำเนินการคำสั่ง สิ่งนี้มีประโยชน์หากคุณต้องการให้ xargs เรียกใช้แอปพลิเคชันแบบโต้ตอบ

หรือ:

find . -name "*.java" -type f -print0 | xargs -o -0 vim

หมายเหตุ: การใช้-print0/ -0จะสนับสนุนชื่อไฟล์ที่มีช่องว่าง


find+ BSDxargs

บน Unix / macOS คุณสามารถลองวิธีแก้ปัญหาต่อไปนี้:

find . -name '*.java' | xargs -J% sh -c 'vim < /dev/tty $@'

คุณยังสามารถใช้ไวยากรณ์การแทนคำสั่งได้เช่น:

vim $(find . -name '*.java')
vim `find . -name '*.java`

หรือใช้ GNU parallelแทนxargsบังคับให้จัดสรร tty ตัวอย่างเช่น:

find . -name '*.java' | parallel -X --tty vi

หมายเหตุ: parallelบน Unix / OSX จะไม่ทำงานเนื่องจากมีพารามิเตอร์ที่แตกต่างกันและไม่รองรับ tty

คำสั่งยอดนิยมอื่น ๆ อีกมากมายให้การจัดสรรแบบหลอกเช่นกัน (เหมือน-tในssh) ดังนั้นให้ตรวจสอบเพื่อขอความช่วยเหลือ

ข้อเสนอแนะอื่น ๆ จะใช้:

ที่เกี่ยวข้อง:


ฉัน GNU ไม่ได้xargs -Jดูเหมือนว่าจะเป็นตัวเลือก MacOS (BSD) ที่ไม่ปรากฏในรุ่น GNU
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

12

คำแนะนำการแก้ไขปัญหา: ใช้บัฟเฟอร์เป็นตัวนำทางระบบไฟล์

ใช้vim -คำสั่งเพื่ออ่านรายการพา ธ จาก stdin Vim :help --อธิบายสิ่งนี้: 1

เริ่มแก้ไขบัฟเฟอร์ใหม่ซึ่งเต็มไปด้วยข้อความที่อ่านจาก stdin คำสั่งที่ปกติจะอ่านจาก stdin จะถูกอ่านจาก stderr ตัวอย่าง:

find . -name "*.c" -print | vim -

จากนั้นคุณสามารถใช้gfหรือCtrl-wCtrl-fนำทางไปยังไฟล์ในบัฟเฟอร์เดียวกันหรือในหน้าต่างแยกใหม่ตามลำดับ

คำแนะนำการแก้ปัญหาชั่วคราว: รายการอาร์กิวเมนต์

อีกวิธีที่ยอดเยี่ยมคือการใช้รายการอาร์กิวเมนต์ของ Vim :argadd **/*.javaคำสั่งจะเติมรายการอาร์กิวเมนต์เป็นกลุ่มที่มีไฟล์จาวาพบภายในไดเรกทอรีปัจจุบันซ้ำ จากนั้นคุณสามารถใช้:nextและ:prevเพื่อย้ายระหว่างไฟล์


1 ตัวแรก-จะบอกกลุ่มที่คุณต้องการค้นหาวิธีใช้สำหรับตัวเลือกบรรทัดคำสั่งตัวที่สองคือการตั้งค่าสถานะบรรทัดคำสั่งที่คุณกำลังค้นหา อ่าน:help help-contextเคล็ดลับเพิ่มเติมเช่นนี้


8

นอกจากนี้resetคุณสามารถลอง:

stty sane

ซึ่งควรทำให้เทอร์มินัลของคุณสามารถใช้งานได้อีกครั้ง

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


สิ่งนี้ไม่ตอบคำถาม แต่มันช่วยฉันได้ +1
Reinstate Monica iamnotmaynard

นี่ตอบคำถามของฉัน;) แม้ว่าหลังจากอ่าน OP มากขึ้นฉันก็resetควรจะคิดเช่นกัน
Sridhar Sarnobat

1

เหตุผลก็คือว่าxargsชุดstdinไป/dev/nullในขณะที่vimความต้องการที่จะเป็นstdin/dev/tty


xargsวิธีการแก้ปัญหาBSD (เช่น Mac):

echo -e 'file1\nfile2' | xargs -o vim

-oชุดstdinของกระบวนการเด็ก xarg ของ ( vimในกรณีนี้) dev/ttyเพื่อ


xargsโซลูชันGNU (เช่น Linux):

GNU xargsไม่มี-oตัวเลือก แต่คุณจะต้องใช้วิธีแก้ปัญหาที่ซับซ้อนมากขึ้น (หมายเหตุ: มันเป็นสิ่งสำคัญมากที่จะมีzeroสตริงต่อท้ายอย่าลืมมัน)

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

คุณสามารถทำให้เป็นนามแฝงได้:

alias vimin='xargs bash -c '\''</dev/tty vim "$@"'\'' zero'
echo -e 'file1\nfile2' | vimin

คำอธิบายโดยละเอียดของโซลูชัน GNU xargs

เรามาทำลายมันทีละขั้นตอน:

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

1. xargsเพียงผนวกstdinท้ายของสตริงดังนั้นxargsจะดำเนินการนี้:

    bash -c '</dev/tty vim "$@"' zero file1 file2

2. รูปแบบคือbash -cbash -c 'COMMAND_STRING' $0 $1 $2 etc

"$@"ขยายไปยังพารามิเตอร์ตำแหน่ง"$1", "$2"ฯลฯ ซึ่งไม่รวม "$ 0" เนื่องจากเป็นพารามิเตอร์พิเศษสำหรับชื่อสคริปต์ไม่ใช่พารามิเตอร์ตำแหน่ง นี่คือเหตุผลที่เราต้องเพิ่มสตริงหุ่นzero(มันสามารถเป็นสตริงใด ๆ ) $0เพื่อใช้เป็นสถานที่สำหรับ มิฉะนั้นคุณจะสูญเสียไฟล์แรก

ดังนั้นหลังจากที่คุณขยาย"$@"คุณจบลงด้วย:

    bash -c '</dev/tty vim file1 file2' 

3. bash -cจะดำเนินการ COMMAND_STRING:

    </dev/tty vim file1 file2 

</dev/ttyตั้งค่าเป็นstdinเพื่อ/dev/ttyให้vimสามารถทำงานในโหมดโต้ตอบ


+1 นี่น่าจะเป็นคำตอบที่ซ้ำกับการโหวตมากที่สุด แต่ไม่ใช่ $0ยึด (ที่นี่ "ศูนย์") เป็นกุญแจสำคัญ
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

0

ฉันพบว่าคำตอบทั้งหมดเหล่านี้ขาดไป หลังจากที่ต้องดิ้นรนกับปัญหา xargs วิธีที่ง่ายที่สุดสำหรับฉัน! - ในการค้นหาและเปิดเหล่านี้ในกล่องทั่วไปมีดังต่อไปนี้:

vim -O `grep -lir mySearchTerm *`

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

มีเวลาและสถานที่สำหรับfind . -path ./node_modules -prune -o -name '*.js' | xargs grep -i mySearchTermประกอบกับการเปิดไฟล์ผ่าน vim และวิธีอื่น ๆ สำหรับฉันนั่นไม่ค่อย

หวังว่านี่จะช่วยใครซักคน


2
FWIW ขอแนะนำว่าอย่าใช้สัญลักษณ์ backticks ดั้งเดิมและใช้$(...)แทน มันไม่สำคัญในบรรทัดคำสั่งของคุณเหมือนในสคริปต์ แต่ฉันคิดว่ามันยังดีกว่าที่จะใช้ในคำตอบของคุณ :) (อ้างอิงที่นี่และที่นี่ )
statox
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.