É possível ler a entrada do usuário do STDIN enquanto emaranha um bloco de origem?


10

É possível ler a entrada do usuário do STDIN enquanto emaranha um bloco de origem org-babel-tangle?

Estou ciente disso: Org Mode Babel - avaliação interativa de blocos de código .

Isso não ajuda a resolver esse caso de uso específico, pois ainda não permite a entrada adequada de STDIN do shell, mas simula apenas uma entrada limitada internamente para o Emacs.

fundo

Eu gostaria de usar o Babel da organização para aprender novas linguagens de programação (Perl e Bash) executando alguns tutoriais em um arquivo organizacional.

O problema é que muitos tutoriais contam com o STDIN. Por exemplo, se alguém executar o seguinte perl tidbit:

#+BEGIN_SRC perl :tangle hello-name.pl  :results output :export code
use 5.010;
use strict;
use warnings;

say "What is your name?";
my $name=<STDIN>;
say "Hello $name, how are you?";

#+END_SRC

O Emacs não aguardará a interação do usuário digitar corretamente um nome no STDIN e produzirá imediatamente:

#+RESULTS:
: What is your name?
: Hello , how are you?

A mesma coisa usando um exemplo do bash. Este:

#+BEGIN_SRC sh  :results output :export code :tangle dir-input.sh
#!/bin/bash

if [ -z "$TEST_DIR" ]
then
    echo "TEST_DIR was not set, please enter the path: "
    read input_variable
    export TEST_DIR=$input_variable
fi
#+END_SRC

Não esperará pela entrada do usuário e o Emacs retornará imediatamente isso:

#+RESULTS:
: TEST_DIR was not set, please enter the path: 

Existe uma maneira nativa do Emacs aguardar a entrada em um bloco emaranhado em execução?

Caso contrário, por favor, dê algumas dicas sobre como escrever algo como uma tangle-and-run-via-shell-bufferfunção que:

  • Emaranhe o bloco de código no ponto, salvando com o nome de arquivo fornecido,
  • execute o arquivo correspondente em um shellbuffer visível ,
  • possivelmente aceitando informações do usuário,
  • e finalmente informando STDOUT, se houver, para #+RESULTS:?

Se esse recurso ainda não foi implementado na Org, como alguém poderia implementá-lo com o elisp?


Atualização: Depois de pesquisar e estudar mais os manuais do Emacs e elisp, parece que a maneira de fazer isso seria alavancar o Comint , como talvez make-comint-in-buffer.

(make-comint-in-buffer "*cmd-buffer*" nil "perl" nil "hello-name.pl")

Infelizmente, isso está na minha cabeça agora 😣

Respostas:


4

Tente isto

Nota : Feito as seguintes pequenas alterações no seu bloco de código:

  • Movido #!/bin/bashpara o cabeçalho do bloco de código :shebang #!/bin/bashpara definir automaticamente as permissões de arquivo executável quando o bloco é emaranhado dir-input.sh.

  • Adicionado código de depuração para mostrar $TEST_DIRfoi atribuído corretamente a partir de read input_variable.

#+BEGIN_SRC sh  :results output :export code :tangle dir-input.sh :shebang #!/bin/bash

if [ -z "$TEST_DIR" ]
then
    echo "TEST_DIR was not set, please enter the path: "
    read input_variable
    export TEST_DIR=$input_variable
    echo "# export TEST_DIR=$TEST_DIR"
fi
#+END_SRC   

Em seguida, criou um novo bloco de código para chamar o arquivo emaranhado ./dir-input.sh.

#+BEGIN_SRC sh :results output :shebang #!/bin/bash  :var USER_INPUT=(read-string "Test Dir: ")
  echo $USER_INPUT | ./dir-input.sh 
#+END_SRC

Cabeçalho da nota :var USER_INPUT=(read-string "Test Dir: ")

Este cabeçalho exibirá um Test Dir:prompt na minibufferjanela quando o bloco de código for executado usando a C-c C-c.

Digite o caminho, por exemplo, / path / to / test / dir enter

e o bloco passará a entrada para a ./dir-input.shvia STDIN. Você deve ver o seguinte#+RESULTS:

#+RESULTS:
: TEST_DIR was not set, please enter the path: 
: # export TEST_DIR=/path/to/test/dir

Espero que tenha ajudado!


Código testado com:
GNU Emacs 24.4.1 (x86_64-apple-darwin14.0.0, NS apple-appkit-1343.14) da
versão 2014-12-25 org-mode: 8.3.2


Isso ajuda bastante, obrigado. Uma maneira criativa de usar vars, muito instrutiva. Eu estou querendo saber como eu iria capturar STDIN "totalmente", tipo de falar, ou seja, como se pudesse a partir do shell nativo? Por exemplo, para poder ler novas linhas e controlar caracteres (ao lado de CTRL-D)?
GSL

11
@gsl - BTW - Ainda estou trabalhando em uma nova resposta para a pergunta sobre várias linhas e caracteres de controle. Se você descobrir isso antes de mim, poste sua resposta.
Melioratus 23/06

Muito obrigado por preparar uma nova resposta. Ainda estou procurando uma solução funcional. Não consigo descobrir sozinho, ainda acima da minha cabeça agora. Estou escolhendo sua resposta e, quando a nova aparecer, selecione-a mais tarde.
GSL

Oi @melioratus - você conseguiu encontrar uma maneira de lidar com várias linhas e controlar caracteres? Isso seria bastante útil em muitos casos.
gsl 12/03

11
@gsl - Obrigado por acompanhar! Você está lendo corretamente o stdin seria realmente útil e eu ainda estou procurando! Eu progredi lendo stdin no buffer nomeado na linha de comando e depois chamei o elisp para ler o buffer multilinha na variável. Isso funciona ao ler de um canal, mas infelizmente ainda não está disponível para streaming em stdin, ou seja, tail file |funciona, mas não tail -f file |. Examinarei minhas anotações e adicionarei meu exemplo de multilinha parcialmente funcional como nova resposta. Obrigado pelo lembrete!
Melioratus 12/03
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.