Como fazer o Emacs ler buffer do stdin no início?


40

Com o Vim eu posso fazer facilmente

$ echo 123 | vim -

É possível fazer com o 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

É realmente impossível ler um buffer de um pipe unix?

Edit : Como solução, escrevi um wrapper chamado emacspipe:

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

Respostas:


15

Correto, é impossível ler um buffer do stdin.

A única menção de stdin nas páginas de informações do Emacs é esta , que diz:

No modo em lote, o Emacs não exibe o texto que está sendo editado e os caracteres de interrupção padrão do terminal, como C-ze C-ccontinuam tendo seu efeito normal. As funções prin1, prince print saída para stdoutem vez da área de eco, enquanto messagee mensagens de erro de saída para stderr. As funções que normalmente seriam lidas no minibuffer recebem sua entrada stdin.

E a readfunção pode ler stdin, mas apenas no modo de lote.

Portanto, você não pode nem contornar isso escrevendo elisp personalizado.


10
Não quero desrespeitar ninguém, mas isso é repugnante. Este é um recurso básico do editor e o GNU EMACS existe há décadas. Ele deve ser incorporado.
user787832 6/02/2015

35

Você pode usar a substituição do processo :

$ emacs --insert <(echo 123)

Essa é definitivamente a resposta que mais se aproxima da funcionalidade do Vim. Praticamente apenas movendo a peça canalizada para uma substituição de subprocesso.
precisa saber é o seguinte

@dbmikus Não consigo decidir qual é a minha preferida entre a minha e a de Tomasz Obrębski.
Andrew Wood

Resultados de Tomasz em me recebendo o seguinte erro por algum motivo: emacs: standard input is not a tty
dbmikus

Ah, de fato! Eu assumi que ele tinha testado antes de postar.
Andrew Wood

11
Talvez dependa do mês.
dbmikus

14

Você pode redirecionar para um arquivo e abrir o arquivo. por exemplo

echo 123 > temp; emacs temp

O jweede observa que, se você deseja que o arquivo temporário seja removido automaticamente, você pode:

echo 123 > temp; emacs temp; rm temp

A maneira do Emacsy fazer isso é executar o comando shell no Emacs .

M-! echo 123 RET

Isso fornece um buffer chamado * Shell Command Output * com os resultados do comando.


Sim, eu sei que existe uma maneira emacsy, mas eu esperava que pudesse ser usada de maneira unixy. Criar um arquivo temporário não é uma opção muito boa (lembre-se de excluí-lo mais tarde).
sastanin 31/08/09

11
como:echo 123 > temp; emacs temp; rm temp
jweede 31/08/2009

2
Em geral, existe uma alta impedância entre o Emacs e o Unix. Ou pelo menos entre o Emacs e o fluxo de trabalho tradicional do Unix.
Richard Hoskins

2
@jweede Se você quiser adicionar M-! parte da minha resposta para a sua, então eu poderia excluir minha resposta. Há uma grande sobreposição em nossas respostas, mas acho que o meta-bang é importante para futuros leitores.
Richard Hoskins

11
temp já pode existir no diretório atual, não é seguro; como uma solução, eu escrevi um invólucro: TMP=$(mktemp) && cat > $TMP && emacs23 $TMP ; rm $TMP. Obrigado a todos!
Sastanin

9

É possível, consulte https://stackoverflow.com/questions/2879746/idomatic-batch-processing-of-text-in-emacs

Aqui está o eco em um script emacs (copiado do link acima):

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

ou para ler em um buffer e imprimi-lo de uma só 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))
    ))

6

É possível criar uma função shell simples, que funciona como está lendo no stdin (embora na verdade esteja gravando em um arquivo temporário e depois lendo). Aqui está o código que estou 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
}

Você apenas usa a função como um alias para o emacs, por exemplo

echo "hello world" | e -

ou normalmente de arquivos

e hello_world.txt

Substituir emacspor emacsclientna função também funciona.


Isso funciona bem para mim, mas _emacsfun deve ser emacsclient -c -t $@, ou pelo menos solte a opção -n. páginas man com emacsclient -t --eval "(man \"$1\")" --eval "(delete-window)" (e agora você pode helm-swoopseu caminho para Man Glória!)
Alejandro

11
Esta é a única resposta que eu poderia trabalhar com o emacsclient. Eu criei um script de shell com a idéia básica para que eu possa chamá-lo da configuração do i3. +1
ergosys 8/03

6

Isso funciona:

echo 123 | emacs --insert <(cat)

mas, por alguma razão, apenas no emacs de modo gráfico (Gnome, Konsole, GNU Emacs 23.4.1). O comando:

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

gera um erro 'emacs: entrada padrão não é um tty'. O mesmo erro aparece quando tentado no console de texto não processado.


echo 123 | exec emacs -nw --insert <(cat) </dev/ttyDeveria trabalhar.
Pyrocrasty 16/05

Isso funciona; por que o exec? Isso também funciona: emacs -nw --insert <(eco 123) </ dev / tty
RoyM 28/15

Go figura: funciona lindamente no Emacs (w32) no Cygwin, onde muitas outras configurações do meu não fazer
Charles Roberto Canato

5

Outra possibilidade não mencionada em nenhuma das respostas anteriores é usar /dev/stdinse a sua variante Unix escolhida a possuir.

Simplesmente tentar abrir /dev/stdindiretamente não funciona, porque o Emacs faz algumas verificações e depois relata Symbolic link that points to nonexistent file. (E se o Emacs permitir que você carregue o arquivo, tente salvá-lo novamente, como /dev/stdinraramente faria o que o usuário esperava.)

No entanto, a combinação /dev/stdincom o --insertargumento funciona:

echo 123 | emacs --insert /dev/stdin

Note-se que esta versão só funciona com o X. Se você precisar de uma solução que funcione em um terminal, sugiro que procure outra resposta .


Eu recebi a emacs: standard input is not a ttymensagem testando-o no linux e bsd

11
@ Chinggis6 Parece que minha sugestão só funciona ao usar o X11. Se eu digitar pela primeira vez unset DISPLAY, recebo a mesma mensagem de erro que você.
kasperd

11
@ Chinggis6 Eu atualizei a minha resposta em apontar que ele precisa de X para o trabalho e apontou para uma resposta que funciona sem X.
kasperd

2

de imediato, algo como:

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

ou

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

é uma opção. O Emacs simplesmente não se integra ao UNIX da maneira que o vim faz.


11
É surpreendente que o Emacs não se integre melhor ao UNIX, dada a sua história e que um dos princípios fundamentais do UNIX é que "tudo é um arquivo". Parece intuitivo canalizar a saída diretamente para o Emacs.
SabreWolfy

5
@SabreWolfy Enquanto o GNU Emacs é mais comumente hospedado no Unix, não é "um programa Unix" do jeito que o Vim é, mas sim uma máquina Lisp que implementa um editor de texto independente de plataforma. (Veja a resposta de Richard Hoskins; a "maneira do Emacs" de fazer isso não é canalizar o comando shell para o Emacs, mas ter que invocar o comando shell do Emacs via M-!, que captura automaticamente a saída resultante em um buffer temporário.) guerras à parte, nenhum editor é "melhor" que o outro; eles só têm perspectivas muito diferentes sobre praticamente tudo.
Aaron Miller

exceto quando você está em uma concha e quer fazer algo como curl foo.bar | vim -.. me desculpe. Eu quis dizer curl foo.bar | emacs, exceto que você não pode fazer isso
dylnmc
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.