Как вызвать редактор 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

Я нахожу это громоздким и пытаюсь изучить bash-скрипты, и я хотел бы сделать этот процесс намного проще, написав команду, которая запускает редактор и когда редактор закрывает канал, выводит его в stdout. Тогда я смогу выполнить команду как quickedit | pandoc -o file.pdf.

Я не уверен, как это будет работать. Я уже написал функцию для автоматизации этого, следуя точному рабочему процессу, указанному выше, плюс некоторые дополнения. Он генерирует случайную строку в качестве имени файла и передает ее в vim при вызове функции. Когда пользователь выходит из vim, сохраняя файл, функция выводит файл на консоль, а затем удаляет файл.

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самого vim, его нельзя использовать в качестве редактора, потому что весь вывод ограничен каналом.

Мне интересно, есть ли какие-нибудь обходные пути к этому, чтобы я мог передать вывод своей quickeditфункции. Неоптимальной альтернативой является запуск отдельного редактора, скажем, возвышенного текста, но я действительно хочу остаться в терминале.

theideasmith
источник
Изнутри vim, введите команду :w !pandoc -o file.pdf? (Примечание: пробел между wи !является существенным.)
John1024
Хорошо, это здорово. Я не знал, что вы можете передать вывод vim изнутри самого vim. Это служит моим целям, но насколько я знаю в будущем, возможно ли решить мою проблему именно так, как я намеревался ее решить?
theideasmith
Можете ли вы опубликовать свою функцию? Что вы имеете в виду, когда говорите о проблеме, с которой вскоре столкнулись (второй последний абзац)? Я не понимаю этого.
Лукас
5
Кроме того, вы должны использовать,mktemp а не изобретать его небезопасным способом.
Wildcard
Как новый пользователь bash, каковы угрозы безопасности при переизобретении 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) .
Матеуш Пиотровский
20

Вы можете сделать это из Vim:

:w !pandoc -o file.pdf

Или даже записать буфер в сложный конвейер:

:w !grep pattern | somecommand > file.txt

И тогда вы можете выйти из Vim без сохранения:

:q!

Однако, учитывая ваш конкретный вариант использования, вероятно, есть лучшее решение, если использовать его в viкачестве редактора командной строки. Предполагая, что вы используете bash:

set -o vi

Это устанавливает ваши сочетания клавиш в vi. Таким образом, вы можете редактировать свои команды прямо в командной строке с помощью основных viсочетаний клавиш, нажимая <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), и все это будет выполнено как команда оболочки.

Он также будет доступен в истории команд вашей оболочки.

Wildcard
источник
1
Если вы предпочитаете сохранять привязки клавиш Emacs, вы все равно можете использовать Vim для редактирования командных строк, установив для EDITORпеременной среды значение vimи нажав, Ctrl-Xа затем Ctrl-Eредактируя командную строку.
Энтони Дж. - справедливость для Моники
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.

Запуск программы из vim

Как я уже упоминал в комментариях, vim может передать файл команде. Например, изнутри vim введите команду :w !pandoc -o file.pdf(Примечание: пробел между w и! Необходим).

John1024
источник
2
Хороший ответ. Этот вопрос напрямую отвечает на вопрос пользователя и предлагает быстрое и элегантное решение: перенаправить vim в / dev / tty! Просто!
Майк С
Я использую Zsh; trap '...' exitне удается, но, trap '...' EXITкажется, работает. Я не знаю много о захвате, но мой общий подход к временным файлам заключается в использовании mktmp [--suffix=...]. Кроме того, vim <outfile> -c '...' >/dev/ttyработает как обычно, пока файл не загружен, затем выполняет заданную цепочку команд, в том числе, :wqесли вы хотите пропустить этап редактирования. Я тоже использовал set | grep -a EXITи нашел signals=(EXIT ... DEBUG).
Джон П
5

Убедитесь, что vimон установлен в качестве вашего редактора по умолчанию (например, export EDITOR=vimв вашем .bash_profileили .bashrc. Затем, в любом приглашении, вы можете ввести Ctrl-, Xа затем Ctrl- E. Это откроет вашу текущую командную строку в настроенном редакторе (например vim). Внесите изменения, сохраните и выйти, и команда будет выполнена так, как если бы вы ввели ее в командной строке, включая конвейеры и тому подобное.

DopeGhoti
источник