Cara menjalankan editor vim dan mem-pipe output ke bash

34

Kadang-kadang saya perlu menulis teks dan kemudian menyalurkan teks itu ke perintah lain. Alur kerja saya yang biasa berjalan seperti ini:

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

Saya menemukan ini rumit dan berusaha untuk belajar scripting bash Saya ingin membuat proses lebih sederhana dengan menulis perintah yang membuka editor dan ketika editor menutup pipa output editor ke stdout. Maka saya bisa menjalankan perintah sebagai quickedit | pandoc -o file.pdf.

Saya tidak yakin bagaimana ini akan berhasil. Saya sudah menulis fungsi untuk mengotomatisasi ini dengan mengikuti alur kerja yang tepat di atas ditambah beberapa tambahan. Ini menghasilkan string acak untuk bertindak sebagai nama file dan meneruskannya ke vim ketika fungsi dipanggil. Ketika pengguna keluar vim dengan menyimpan file, fungsi mencetak file ke konsol dan kemudian menghapus file.

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

Masalah saya segera temui adalah ketika saya melakukan sesuatu seperti quickedit | commandvim itu sendiri tidak dapat digunakan sebagai editor karena semua output dibatasi ke pipa.

Saya bertanya-tanya apakah ada solusi untuk ini, sehingga saya bisa menyalurkan output dari quickeditfungsi saya . Alternatif suboptimal adalah menjalankan editor terpisah, katakan teks luhur, tapi saya benar-benar ingin tinggal di terminal.

theideasmith
sumber
Dari dalam vim, keluarkan perintah :w !pandoc -o file.pdf? (Catatan: ruang antara wdan !sangat penting.)
John1024
Ok - itu bagus. Saya tidak tahu Anda bisa mem-pipe output vim dari dalam vim itu sendiri. Ini melayani tujuan saya, tetapi untuk pengetahuan saya di masa depan, apakah mungkin untuk menyelesaikan masalah saya persis seperti yang saya inginkan untuk diselesaikan?
theideasmith
Bisakah Anda memposting fungsi Anda? Apa maksud Anda ketika Anda berbicara tentang masalah yang segera Anda temui (paragraf terakhir kedua)? Saya tidak mengerti.
Lucas
5
Sebagai tambahan, Anda harus menggunakanmktemp daripada menciptakannya kembali dengan cara yang tidak aman.
Wildcard
Sebagai pengguna bash baru, apa bahaya keamanan dari menciptakan kembali mktemp?
theideasmith

Jawaban:

42

vipe adalah program untuk mengedit saluran pipa:

command1 | vipe | command2

Anda mendapatkan editor dengan output lengkap command1, dan ketika Anda keluar, konten diteruskan ke command2melalui pipa.

Dalam hal ini, tidak ada command1. Jadi, Anda bisa melakukan:

: | vipe | pandoc -o foo.pdf

Atau:

vipe <&- | pandoc -o foo.pdf

vipemengambil EDITORdan VISUALvariabel, sehingga Anda dapat menggunakannya untuk membuka Vim.

Jika Anda belum menginstalnya, vipetersedia dalam moreutilspaket; sudo apt-get install moreutils, atau apa pun yang setara dengan flavour Anda.

muru
sumber
1
Untuk pengguna Mac yang telah tiba di sini: moreutilstersedia di Homebrew.
vergenzt
Untuk pengguna FreeBSD: moreutilstersedia untuk diinstal melalui pkg (8) .
Mateusz Piotrowski
20

Anda dapat melakukan ini dari dalam Vim:

:w !pandoc -o file.pdf

Atau bahkan menulis buffer ke dalam pipeline yang kompleks:

:w !grep pattern | somecommand > file.txt

Dan kemudian Anda dapat keluar dari Vim tanpa menyimpan:

:q!

Namun, mengingat kasus penggunaan khusus Anda, mungkin ada solusi yang lebih baik dengan menggunakan visebagai editor baris perintah Anda. Dengan asumsi Anda menggunakan bash:

set -o vi

Ini mengatur ikatan kunci Anda vi. Sehingga Anda dapat mengedit perintah Anda tepat pada baris perintah dengan dasar vikeybindings dengan menekan <Esc>dan kemudian mengetik viperintah seperti x, cw, dll (Anda bisa mendapatkan kembali modus insert dengan menekan i.)

Bahkan lebih baik, dan lebih relevan dengan pertanyaan ini, Anda dapat membuka Vim untuk membuat konten baris perintah Anda secara langsung. Cukup ketik <Esc>vdan Anda akan mendapatkan buffer Vim kosong. Ketika Anda menyimpan dan keluar, itu adalah perintah di baris perintah Anda dan langsung dijalankan. Ini jauh lebih fleksibel daripada mengedit pada baris perintah secara langsung karena Anda dapat menulis seluruh skrip mini jika Anda mau.


Jadi, misalnya, jika Anda ingin menulis beberapa teks rumit dan langsung mengirimkannya ke pandoc, Anda cukup mengetik:

<Esc>v

Kemudian edit buffer Vim hingga Anda memiliki sesuatu seperti:

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

Kemudian simpan dan keluar (dengan :x) dan semuanya akan dijalankan sebagai perintah shell.

Ini juga akan tersedia dalam riwayat perintah shell Anda.

Wildcard
sumber
1
Jika Anda lebih memilih untuk menjaga ikatan tombol Emacs, Anda masih dapat menggunakan Vim untuk mengedit baris perintah dengan mengatur EDITORvariabel lingkungan ke vimdan menekan Ctrl-Xdiikuti dengan Ctrl-Esaat mengedit baris perintah.
Anthony G - keadilan untuk Monica
18

Berjalan di saluran pipa

Mencoba:

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

Kuncinya adalah bahwa, untuk dapat menggunakan secara vimnormal, vimperlu stdout menjadi terminal. Kami melakukannya di sini dengan pengalihan >/dev/tty.

Untuk tujuan keamanan, saya meletakkan file sementara di direktori home pengguna. Untuk lebih lanjut tentang ini, lihat FAQ FAQ Pertanyaan 062 Greg . Ini menghilangkan kebutuhan untuk menggunakan nama file yang tidak jelas.

Contoh:

Ketika vimterbuka, saya mengetik This function succeeded.dan menyimpan file. Hasilnya di layar terlihat seperti:

$ quickedit | grep succeeded
This function succeeded.

Meskipun output dari quickeditdialihkan ke saluran pipa, vimmasih berfungsi normal karena kami telah memberikan akses langsung ke /dev/tty.

Menjalankan program dari dalam vim

Seperti yang saya sebutkan di komentar, vim dapat mengirim file ke perintah. Dari dalam vim, misalnya, berikan perintah :w !pandoc -o file.pdf(Catatan: ruang antara w dan! Sangat penting).

John1024
sumber
2
Jawaban bagus. Yang ini langsung menjawab pertanyaan pengguna, dan menawarkan solusi cepat dan elegan: redirect vim ke / dev / tty! Sederhana!
Mike S
Saya menggunakan Zsh; trap '...' exitgagal tetapi trap '...' EXITtampaknya berfungsi. Saya tidak tahu banyak tentang menjebak, tetapi pendekatan umum saya untuk file sementara adalah menggunakan mktmp [--suffix=...]. Juga, vim <outfile> -c '...' >/dev/ttyberjalan seperti biasa sampai file dimuat, kemudian jalankan rantai perintah yang diberikan, termasuk :wqjika Anda ingin melewati fase pengeditan. Saya juga menggunakan set | grep -a EXITdan menemukan signals=(EXIT ... DEBUG).
John P
5

Pastikan bahwa vimditetapkan sebagai editor default Anda (misalnya export EDITOR=vimdi .bash_profileatau .bashrc. Kemudian, pada prompt apa pun, Anda dapat mengetik Ctrl- Xdiikuti oleh Ctrl- E. Ini akan membuka baris perintah Anda saat ini di editor yang dikonfigurasi (mis vim.). Edit, simpan dan keluar, dan perintah akan dieksekusi seolah-olah Anda telah mengetiknya di baris perintah, termasuk pipa dan sejenisnya.

DopeGhoti
sumber