¿Cómo hacer que Emacs lea el búfer de stdin al inicio?

40

Con Vim puedo hacer fácilmente

$ echo 123 | vim -

¿Es posible hacer con 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

¿Es realmente imposible leer un búfer de una tubería Unix?

Editar : Como solución, escribí un contenedor de shell llamado emacspipe:

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

Respuestas:

15

Correcto, es imposible leer un búfer de stdin.

La única mención de stdin en las páginas de información de Emacs es esta , que dice:

En el modo por lotes, Emacs no muestra el texto que se está editando y los caracteres de interrupción de terminal estándar como C-z y C-csiguen teniendo su efecto normal. Las funciones prin1, princy print de salida a stdouten lugar del área de eco, mientras que messagelos mensajes de error de salida a stderr. En su lugar, las funciones que normalmente se leerían desde el minibúfer toman su entrada stdin.

Y la readfunción puede leer stdin, pero solo en modo por lotes.

Por lo tanto, ni siquiera puede evitar esto escribiendo elisp personalizado.

Trey Jackson
fuente
11
No quiero faltarle el respeto a nadie, pero esto es aborrecible. Esta es una función de editor muy básica y GNU EMACS ha existido durante décadas. Debería estar integrado.
user787832
35

Puede usar la sustitución de procesos :

$ emacs --insert <(echo 123)
Andrew Wood
fuente
Esta es definitivamente la respuesta que se acerca más a la funcionalidad de Vim. Prácticamente solo moviendo la parte entubada a una sustitución de subproceso.
dbmikus
@dbmikus No puedo decidir cuál prefiero entre el mío y el de Tomasz Obrębski ..
Andrew Wood
Los resultados de Tomasz en mí obteniendo el siguiente error por alguna razón: emacs: standard input is not a tty
dbmikus
Oh por cierto! Supuse que lo había probado antes de publicar.
Andrew Wood
1
Tal vez depende del mes.
dbmikus
14

Puede redirigir a un archivo y luego abrir el archivo. p.ej

echo 123 > temp; emacs temp

jweede señala que si desea que el archivo temporal se elimine automáticamente, puede:

echo 123 > temp; emacs temp; rm temp

La forma en que Emacsy hace esto es ejecutar el comando de shell en Emacs .

M-! echo 123 RET

Eso le da un búfer llamado * Salida del comando Shell * con los resultados del comando.

Richard Hoskins
fuente
Sí, sé que hay una forma emacsy, pero esperaba que se usara de manera unixy. Crear un archivo temporal no es una buena opción (tengo que recordar eliminarlo más tarde).
sastanin
1
tales como:echo 123 > temp; emacs temp; rm temp
jweede
2
En general, hay una alta impedancia entre Emacs y Unix. O al menos entre Emacs y el flujo de trabajo tradicional de Unix.
Richard Hoskins el
2
@jweede Si quieres agregar M-! parte de mi respuesta a la suya, entonces podría borrar mi respuesta. Hay una gran superposición en nuestras respuestas, pero creo que el meta-bang es importante para los futuros lectores.
Richard Hoskins el
1
Puede que ya exista temp en el directorio actual, no es seguro; como una solución, escribí un envoltorio: TMP=$(mktemp) && cat > $TMP && emacs23 $TMP ; rm $TMP. ¡Gracias a todos!
sastanin
9

Es posible, ver https://stackoverflow.com/questions/2879746/idomatic-batch-processing-of-text-in-emacs

Aquí hay eco en un script de emacs (copiado del enlace anterior):

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

o para leerlo en un búfer y luego imprimirlo todo de una vez

#!/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))
    ))
cwitte
fuente
6

Es posible crear una función de shell simple que funciona mientras lee desde stdin (aunque de hecho está escribiendo en un archivo temporal y luego leyendo eso). Aquí está el código que estoy usando:

# 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
}

Simplemente usa la función como un alias para emacs, por ejemplo

echo "hello world" | e -

o como normal de los archivos

e hello_world.txt

Reemplazar emacspor emacsclienten la función también funciona.

dshepherd
fuente
Esto funciona bien para mí, pero _emacsfun debería ser emacsclient -c -t $@, o al menos, soltar la opción -n. páginas de manual con emacsclient -t --eval "(man \"$1\")" --eval "(delete-window)" (¡y ahora puedes helm-swoopllegar a Man Glory!)
Alejandro
1
Esta es la única respuesta que podría obtener para trabajar con emacsclient. Hice un script de shell a partir de la idea básica para poder llamarlo desde la configuración de i3. +1
ergosys
6

Esto funciona:

echo 123 | emacs --insert <(cat)

pero, por alguna razón, solo con emacs en modo gráfico (Gnome, Konsole, GNU Emacs 23.4.1). El comando:

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

genera un error 'emacs: la entrada estándar no es un tty'. El mismo error aparece cuando se intenta en la consola de texto sin formato.

Tomasz Obrębski
fuente
echo 123 | exec emacs -nw --insert <(cat) </dev/ttyDeberia trabajar.
pirócrata
Eso funciona; ¿Por qué el ejecutivo? Esto también funciona: emacs -nw - inserción <(echo 123) </ dev / tty
RoyM
Vaya figura: funciona maravillosamente en Emacs (w32) en Cygwin, donde muchas otras configuraciones mías no lo hacen
Charles Roberto Canato
5

Otra posibilidad que no se menciona en ninguna de las respuestas anteriores es usar /dev/stdin si la variante Unix elegida la tiene.

Simplemente intentar abrir /dev/stdindirectamente no funciona, porque Emacs hace algunas verificaciones y luego informa Symbolic link that points to nonexistent file. (Y si Emacs le hubiera permitido cargar el archivo, intente guardarlo nuevamente como/dev/stdin que raramente haría lo que el usuario esperaba).

Sin embargo, combinar /dev/stdincon el --insertargumento funciona:

echo 123 | emacs --insert /dev/stdin

Cabe señalar que esta versión solo funciona cuando se usa X. Si necesita una solución que funcione en un terminal, le sugiero que busque otra respuesta .

kasperd
fuente
recibí un emacs: standard input is not a ttymensaje probándolo en linux y bsd
1
@ Chinggis6 Parece que mi sugerencia solo funciona cuando uso X11. Si primero escribo unset DISPLAY, recibo el mismo mensaje de error que usted.
kasperd
1
@ Chinggis6 Actualicé mi respuesta para señalar que necesita X para funcionar y señalé una respuesta que funciona sin X.
kasperd
2

de improviso, algo como:

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

o

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

Es una opción. Emacs simplemente no se integra con UNIX como lo hace vim.

jweede
fuente
1
Es sorprendente que Emacs no se integre mejor con UNIX, dada su historia y que uno de los principios clave de UNIX es que "todo es un archivo". Se siente intuitivo canalizar la salida directamente a Emacs.
SabreWolfy
55
@SabreWolfy Si bien GNU Emacs se aloja más comúnmente en Unix, no es "un programa de Unix" como Vim, sino una máquina Lisp que implementa un editor de texto en gran medida independiente de la plataforma. (Vea la respuesta de Richard Hoskins; la "forma de Emacs" de hacer esto no es canalizar el comando de shell en Emacs, sino invocar el comando de shell desde Emacs vía M-!, que captura automáticamente la salida resultante en un búfer temporal). guerras aparte, ninguno de los editores es "mejor" que el otro; simplemente tienen perspectivas muy diferentes en casi todo.
Aaron Miller
excepto cuando estás en una concha y quieres hacer algo como curl foo.bar | vim -... Lo siento. Quiero decir, curl foo.bar | emacsexcepto que no puedes hacer eso
dylnmc