纠缠源代码块时是否可以从STDIN中读取用户输入?


10

在与源块纠缠的同时,是否可以从STDIN中读取用户输入org-babel-tangle

我知道:Org Mode Babel-交互式代码块评估

这无助于解决这个特殊的用例,因为它仍然不允许来自shell的正确STDIN输入,而只能在Emacs 内部模拟有限的输入。

背景

我想使用Org的Babel通过从一个组织文件执行一些教程来学习新的编程语言(Perl和Bash)。

问题在于许多教程都依赖于STDIN。例如,如果运行以下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

Emacs不会等待用户的交互在STDIN上正确键入名称,它将立即输出:

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

使用bash示例也是一样。这个:

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

不会等待用户输入,Emacs将立即返回以下内容:

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

Emacs是否有本地方法来等待正在执行的纠结块上的输入?

如果不是这样,请您提供一些有关如何编写类似tangle-and-run-via-shell-buffer函数的说明:

  • 纠缠代码块,保存给定文件名,
  • 在可见shell缓冲区中执行相应的文件,
  • 可能接受用户的输入,
  • 并最终向STDOUT(如果有)报告#+RESULTS:

如果尚未在Org中实现此功能,如何用elisp来实现呢?


更新:在搜索和研究了更多Emacs和elisp手册之后,似乎可以利用Comint来做到这一点,例如make-comint-in-buffer

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

不幸的是,这现在已经让我感到头疼😣

Answers:


4

尝试这个

注意:对代码块进行了以下较小更改:

  • 移动#!/bin/bash成代码块首部:shebang #!/bin/bash时块被纠结成以自动设置可执行文件的权限dir-input.sh

  • 添加了调试代码以显示$TEST_DIR已从正确分配了调试代码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   

然后创建新的代码块来调用纠结的文件./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

通知标题 :var USER_INPUT=(read-string "Test Dir: ")

使用.exe执行代码块时,此标题将Test Dir:minibuffer窗口中显示提示C-c C-c

输入路径,例如/ path / to / test / dir enter

然后该块会将输入传递给./dir-input.shvia STDIN。您应该看到以下内容#+RESULTS:

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

希望能有所帮助!


测试的代码:
2014年12月25日的GNU Emacs 24.4.1(x86_64-apple-darwin14.0.0,NS apple-appkit-1343.14)
组织模式版本:8.3.2


很有帮助,谢谢。一种新颖的使用var的方法,很有启发性。我想知道如何去捕获STDIN“ wholy”,就像从本地shell可以捕获一样?例如,是否能够读取换行并控制字符(在CTRL-D旁边)?
gsl

1
@gsl-顺便说一句-我仍在研究有关多行和控制字符的新答案。如果您在我之前弄清楚了,请发表您的答案。
Melioratus

非常感谢您准备新的答案。我仍然在寻找一个可行的解决方案。我无法自己弄清楚,现在仍在脑海中。我正在选择您的答案,当您的新答案出现时,请稍后选择。
gsl

嗨@melioratus-您能找到处理多行和控制字符的方法吗?在许多情况下,这将非常有用。
gsl

1
@gsl-感谢您的跟进!您是对的,从stdin读取的信息非常有用,我仍在寻找!我已经从命令行将stdin读入命名缓冲区,然后调用elisp将多行缓冲区读入变量,已经取得了进展。从管道读取时,此方法有效,但不幸的是,尚不适用于流式stdin,即,tail file |但无效tail -f file |。我将仔细阅读我的笔记,并添加部分工作的多行示例作为新答案。感谢您的提醒!
Melioratus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.