Comment faire en sorte que Emacs lise le tampon de stdin au démarrage?

40

Avec Vim, je peux facilement faire

$ echo 123 | vim -

Est-il possible de faire avec 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

Est-il vraiment impossible de lire un tampon à partir d'un pipe Unix?

Edit : En guise de solution, j'ai écrit un wrapper de shell nommé emacspipe:

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

Réponses:

15

Correct, il est impossible de lire un tampon de stdin.

La seule mention de stdin dans les pages d’information Emacs est la suivante :

En mode de traitement par lots, Emacs n'affiche pas le texte en cours d'édition et les caractères d'interruption du terminal standard tels que C-zet C-ccontinuent à produire leur effet normal. Les fonctions prin1, princet la print sortie au stdoutlieu de la zone d'écho, tandis que messageles messages d'erreur sortie stderr. Les fonctions qui liraient normalement à partir du mini-tampon prennent leur entrée à la stdinplace.

Et la readfonction peut lire stdin, mais seulement en mode batch.

Donc, vous ne pouvez même pas contourner ce problème en écrivant elisp personnalisé.

Trey Jackson
la source
11
Je ne veux pas manquer de respect à qui que ce soit, mais c'est odieux. Il s'agit d'une fonctionnalité très élémentaire de l'éditeur et GNU EMACS existe depuis des décennies. Il devrait être intégré.
user787832
35

Vous pouvez utiliser la substitution de processus :

$ emacs --insert <(echo 123)
Andrew Wood
la source
C’est définitivement la réponse qui se rapproche le plus de la fonctionnalité Vim. Plutôt que de déplacer la partie canalisée dans une substitution de sous-processus.
dbmikus
@dbmikus Je ne peux pas décider lequel je préfère entre le mien et celui de Tomasz Obrębski.
Andrew Wood
Les résultats de Tomasz me donnent l'erreur suivante pour une raison quelconque: emacs: standard input is not a tty
dbmikus
Oh vraiment! J'ai supposé qu'il avait testé avant de poster.
Andrew Wood
1
Cela dépend peut-être du mois.
dbmikus
14

Vous pouvez rediriger vers un fichier, puis l'ouvrir. par exemple

echo 123 > temp; emacs temp

jweede note que si vous souhaitez que le fichier temporaire soit automatiquement supprimé, vous pouvez:

echo 123 > temp; emacs temp; rm temp

Pour ce faire, Emacsy exécute la commande shell dans Emacs .

M-! echo 123 RET

Cela vous donne un tampon nommé * Shell Command Output * avec les résultats de la commande.

Richard Hoskins
la source
Oui, je sais qu'il y a moyen d'émacsy, mais j'espérais qu'il pourrait être utilisé de manière unixy. Créer un fichier temporaire n’est pas une très bonne option (je dois me rappeler de le supprimer plus tard).
Sastanin
1
comme:echo 123 > temp; emacs temp; rm temp
jweede
2
En général, il existe une impédance élevée entre Emacs et Unix. Ou du moins entre Emacs et le flux de travail Unix traditionnel.
Richard Hoskins
2
@jweede Si vous voulez ajouter M-! une partie de ma réponse à la vôtre, je pourrais alors supprimer ma réponse. Il y a beaucoup de chevauchement dans nos réponses, mais je pense que la méta-bang est importante pour les futurs lecteurs.
Richard Hoskins
1
temp peut déjà exister dans le répertoire courant, ce n'est pas sûr; comme une solution, je l' ai écrit un emballage: TMP=$(mktemp) && cat > $TMP && emacs23 $TMP ; rm $TMP. Merci à tous!
Sastanin
9

C'est possible, voir https://stackoverflow.com/questions/2879746/idomatic-batch-processing-of-text-in-emacs

Voici echo dans un script emacs (copié à partir du lien ci-dessus):

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

ou de le lire dans un tampon puis de l'imprimer en une seule fois

#!/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
la source
6

Il est possible de créer une fonction shell simple qui fonctionne comme si elle lisait à partir de stdin (bien qu’en réalité, elle écrit dans un fichier temporaire puis la lit). Voici le code que j'utilise:

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

Vous utilisez simplement la fonction comme alias pour emacs, par exemple

echo "hello world" | e -

ou comme d'habitude à partir de fichiers

e hello_world.txt

Le remplacement emacspar emacsclientdans la fonction fonctionne également.

dshepherd
la source
Cela fonctionne bien pour moi, mais _emacsfun devrait l’être emacsclient -c -t $@, ou du moins supprimer l’option -n. pages de manuel avec emacsclient -t --eval "(man \"$1\")" --eval "(delete-window)" (et maintenant vous pouvez helm-swoopvous rendre à Man Glory!)
Alejandro
1
C’est la seule réponse possible pour emacsclient. J'ai créé un script shell à partir de l'idée de base pour pouvoir l'appeler depuis la configuration i3. +1
ergosys
6

Cela marche:

echo 123 | emacs --insert <(cat)

mais, pour une raison quelconque, uniquement avec emacs en mode graphique (Gnome, Konsole, GNU Emacs 23.4.1). La commande:

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

génère une erreur 'emacs: l'entrée standard n'est pas un tty'. La même erreur apparaît lorsque vous essayez dans la console de texte brut.

Tomasz Obrębski
la source
echo 123 | exec emacs -nw --insert <(cat) </dev/ttydevrait marcher.
pyrocrastie
Ça marche; pourquoi l'exec? Cela fonctionne aussi: emacs -nw --insert <(echo 123) </ dev / tty
RoyM
Allez comprendre: fonctionne à merveille sur Emacs (w32) sur Cygwin, là où de nombreux autres paramètres ne me
conviennent
5

Une autre possibilité non mentionnée dans les réponses précédentes est d'utiliser /dev/stdinsi la variante Unix choisie l'a.

Essayer d'ouvrir /dev/stdindirectement ne fonctionne pas, car Emacs effectue quelques vérifications puis génère des rapports Symbolic link that points to nonexistent file. (Et si Emacs vous aurait permis de charger le fichier, essayez de le sauvegarder à nouveau comme le /dev/stdinferait rarement ce que l'utilisateur attendait.)

Cependant, la combinaison /dev/stdinavec l' --insertargument fonctionne:

echo 123 | emacs --insert /dev/stdin

Il est à noter que cette version ne fonctionne que sous X. Si vous avez besoin d'une solution qui fonctionne dans un terminal, je vous suggère de chercher une autre réponse .

Kasperd
la source
J'ai reçu un emacs: standard input is not a ttymessage le testant sur linux et bsd
1
@ Chinggis6 On dirait que ma suggestion ne fonctionne qu'avec X11. Si je tape d’abord unset DISPLAY, j’obtiens le même message d’erreur que vous.
Kasperd
1
@ Chinggis6 J'ai mis à jour ma réponse pour indiquer qu'il doit fonctionner avec X et qu'il a pointé une réponse qui fonctionne sans X.
kasperd
2

désinvolte, quelque chose comme:

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

ou

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

est une option. Emacs ne s'intègre pas avec UNIX comme le fait vim.

Jweede
la source
1
Il est surprenant qu'Emacs ne s'intègre pas mieux avec UNIX, compte tenu de son histoire et que l'un des principes clés d'UNIX est que "tout est un fichier". Il est intuitif de diriger directement les sorties vers Emacs.
SabreWolfy
5
@SabreWolfy Bien que GNU Emacs soit généralement hébergé sous Unix, ce n'est pas "un programme Unix" comme Vim, mais plutôt une machine Lisp qui implémente un éditeur de texte largement indépendant de la plate-forme. (Voir la réponse de Richard Hoskins; la "méthode Emacs" pour ce faire ne consiste pas à diriger une commande shell dans Emacs, mais à avoir invoqué la commande shell depuis Emacs via M-!, qui capture automatiquement la sortie résultante dans un tampon temporaire.) Holy guerres de côté, aucun éditeur n’est "meilleur" que l’autre; ils ont juste des perspectives très différentes sur à peu près tout.
Aaron Miller
sauf quand tu es dans un shell et que tu veux faire quelque chose comme curl foo.bar | vim -.. Je suis désolé. Je voulais dire curl foo.bar | emacssauf que tu ne peux pas faire ça
dylnmc