Як змусити Emacs читати буфер із stdin на початку?


40

З Вімом я легко можу

$ echo 123 | vim -

Чи можна робити з Emacs?

$ echo 123 | emacs23
... Emacs starts with a Welcome message

$ echo 123 | emacs23 -
... Emacs starts with an empty *scratch* buffer and “Unknown option”

$ echo 123 | emacs23 --insert -
... “No such file or directory”, empty *scratch* buffer

Чи справді неможливо прочитати буфер з unix-труби?

Редагувати : Як рішення, я написав обгортку оболонки під назвою emacspipe:

#!/bin/sh
TMP=$(mktemp) && cat > $TMP && emacs23 $TMP ; rm $TMP

Відповіді:


15

Правильно, неможливо прочитати буфер із stdin.

Єдина згадка stdin на інформаційних сторінках Emacs - це , що говорить:

У пакетному режимі Emacs не відображає текст, що редагується, а стандартні символи переривання терміналу, такі як C-zі C-cпродовжують мати свою нормальну дію. Функції prin1, princі print вихід до stdoutзамість області луни, в той час як messageі висновок повідомлень про помилки stderr. Функції, які зазвичай зчитуються з мінібуфера, беруть свій внесок зstdin замість цього .

І то read функцію можна читати з stdin, але тільки в пакетному режимі.

Таким чином, ви навіть не можете обійти це, написавши користувальницьку програму Elisp.


10
Я маю на увазі не неповагу до когось, але це гидко. Це дуже основна функція редактора, і GNU EMACS існує вже десятиліття. Це має бути вбудовано.
user787832

35

Ви можете використовувати підстановку процесу :

$ emacs --insert <(echo 123)

Це, безумовно, відповідь, яка наближається до функціоналу Vim. В основному просто переміщення трубопровідної частини в заміну підпроцесу.
dbmikus

@dbmikus Я не можу визначити, який я віддаю перевагу між моїм і Томашем Обребським ..
Andrew Wood

Результати Томаша мені чомусь отримують таку помилку: emacs: standard input is not a tty
dbmikus

О, справді! Я припускав, що він протестував перед публікацією.
Ендрю Вуд

1
Можливо, це залежить від місяця.
dbmikus

14

Ви можете перенаправити файл, а потім відкрити файл. напр

echo 123 > temp; emacs temp

jweede зазначає, що якщо ви хочете, щоб тимчасовий файл був автоматично видалений, ви можете:

echo 123 > temp; emacs temp; rm temp

Це зробити Emacsy - це запустити команду shell у Emacs .

M-! echo 123 RET

Це дає вам буфер з назвою * Shell Command Output * з результатами команди.


Так, я знаю, що існує emacsy спосіб, але я сподівався, що це може бути використаний unixy спосіб. Створення тимчасового файлу - не дуже приємний варіант (я мушу пам’ятати, щоб видалити його пізніше).
зустріч

1
наприклад:echo 123 > temp; emacs temp; rm temp
jweede

2
Загалом, між Emacs та Unix високий опір. Або принаймні між Emacs та традиційним робочим потоком Unix.
Річард Хоскінс

2
@jweede Якщо ви хочете додати M-! частину моєї відповіді на вашу, тоді я можу видалити свою відповідь. У наших відповідях є велике перекриття, але я думаю, що мета-баг важливий для майбутніх читачів.
Річард Хоскінс

1
temp може вже існувати в поточному каталозі, це не безпечно; як рішення, я написав обгортку: TMP=$(mktemp) && cat > $TMP && emacs23 $TMP ; rm $TMP. Дякую всім!
зустріч

9

Можна, див https://stackoverflow.com/questions/2879746/idomatic-batch-processing-of-text-in-emacs

Ось відлуння у скрипті emacs (скопійовано із вищевказаного посилання):

#!/usr/bin/emacs --script
(condition-case nil
    (let (line)
      (while (setq line (read-from-minibuffer ""))
        (princ line)
        (princ "\n")))
  (error nil))

або прочитати його в буфер, а потім роздрукувати все за один раз

#!/usr/bin/emacs --script
(with-temp-buffer
  (progn
    (condition-case nil
    (let (line)
      (while (setq line (read-from-minibuffer ""))
        (insert line)
        (insert "\n")))
      (error nil))
    (princ (buffer-string))
    ))

6

Це можна створити просту функцію оболонки , яка працює , як він читає зі стандартного вводу (хоча насправді він пише в тимчасовий файл , то читання цього). Ось код, який я використовую:

# The emacs or emacsclient command to use
function _emacsfun
{
    # Replace with `emacs` to not run as server/client
    emacsclient -c -n $@
}

# An emacs 'alias' with the ability to read from stdin
function e
{
    # If the argument is - then write stdin to a tempfile and open the
    # tempfile.
    if [[ $# -ge 1 ]] && [[ "$1" == - ]]; then
        tempfile="$(mktemp emacs-stdin-$USER.XXXXXXX --tmpdir)"
        cat - > "$tempfile"
        _emacsfun --eval "(find-file \"$tempfile\")" \
            --eval '(set-visited-file-name nil)' \
            --eval '(rename-buffer "*stdin*" t))'
    else
        _emacsfun "$@"
    fi
}

Ви просто використовуєте функцію як псевдонім для emacs, наприклад

echo "hello world" | e -

або як звичайно з файлів

e hello_world.txt

Заміна emacsпо emacsclientу функції працює добре.


Це добре працює для мене, але _emacsfun має бути emacsclient -c -t $@, або принаймні відкинути опцію -n. Сторінки чоловіка emacsclient -t --eval "(man \"$1\")" --eval "(delete-window)" (і тепер ви можете знайти helm-swoopсвій шлях до Людини Слави!)
Алехандро

1
Це єдина відповідь, на яку я міг би працювати з emacsclient. Я створив скрипт оболонки з основної ідеї, щоб я міг викликати його з i3 config. +1
ergosys

6

Це працює:

echo 123 | emacs --insert <(cat)

але, чомусь, лише з emacs з графічним режимом (Gnome, Konsole, GNU Emacs 23.4.1). Команда:

echo 123 | emacs -nw --insert <(cat)

генерує помилку 'emacs: стандартний ввід не tty'. Така ж помилка з’являється при спробі в текстовій консолі.


echo 123 | exec emacs -nw --insert <(cat) </dev/ttyповинні працювати.
пірокрастія

Це працює; чому exec? Це також працює: emacs -nw --insert <(echo 123) </ dev / tty
RoyM

Погляньте: чудово працює на Emacs (w32) на Cygwin, де немає інших моїх налаштувань
Чарльз Роберто Канато

5

Ще одна можливість, яка не згадується в жодній з попередніх відповідей, - це використовувати, /dev/stdinякщо у вас вибраний варіант Unix.

Просто спроба відкрити /dev/stdinбезпосередньо не працює, оскільки Emacs робить кілька перевірок, а потім звітів Symbolic link that points to nonexistent file. (І якщо Emacs дозволив би вам завантажити файл, то спробуйте зберегти його знову, як /dev/stdinрідко робити те, що очікував користувач.)

Однак поєднання /dev/stdinз --insertаргументом працює:

echo 123 | emacs --insert /dev/stdin

Слід зазначити, що ця версія працює лише під час використання X. Якщо вам потрібне рішення, яке працює в терміналі, я пропоную вам переглянути іншу відповідь .


У мене з'явилося emacs: standard input is not a ttyповідомлення про тестування його на Linux та bsd

1
@ Chinggis6 Схоже, моя пропозиція працює лише під час використання X11. Якщо я вперше введу unset DISPLAY, я отримаю те саме повідомлення про помилку, як і ви.
kasperd

1
@ Chinggis6 Я оновив свою відповідь, щоб зазначити, що їй потрібен X для роботи, і вказав на відповідь, яка працює без X.
kasperd

2

наче, щось на кшталт:

$ echo 123 > tmp.txt; emacs tmp.txt

або

$ echo 123 > tmp.txt; emacs tmp.txt; rm tmp.txt

є варіантом. Emacs просто не інтегрується з UNIX так, як це робить vim.


1
Дивно, що Emacs не краще інтегрується з UNIX, враховуючи його історію і що одним із ключових принципів UNIX є те, що "все є файлом". Інтуїтивно зрозуміло, що виводити трубу безпосередньо в Emacs.
SabreWolfy

5
@SabreWolfy У той час як GNU Emacs найчастіше розміщується на Unix, це не "програма Unix", якою є Vim, а швидше машина Lisp, що реалізує текстовий редактор, що не залежить від платформи. (Див. Відповідь Річарда Хоскінса; "спосіб Emacs" цього не полягає в передачі команди оболонки в Emacs, а в тому, щоб викликати команду оболонки всередині Emacs через M-!, яка автоматично фіксує отриманий результат у тимчасовий буфер.) Holy війни вбік, жоден редактор не "кращий", ніж інші; у них просто дуже різні погляди на майже все.
Аарон Міллер

за винятком випадків, коли ви знаходитесь в оболонці і хочете зробити щось на кшталт curl foo.bar | vim -.. Мені шкода. Я мав на увазі, curl foo.bar | emacsкрім того, що ви не можете цього зробити
dylnmc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.