เป็นไปได้หรือไม่ที่จะอ่านอินพุตของผู้ใช้จาก STDIN ขณะที่กำลังบล็อกซอร์สบล็อก?


10

เป็นไปได้ไหมที่จะอ่านอินพุตของผู้ใช้จาก STDIN ในขณะที่กำลังบล็อกซอร์สด้วยorg-babel-tangle?

ผมตระหนักถึงเรื่องนี้: Org โหมดบาเบล - code อินเตอร์แอคทีประเมินบล็อก

นั่นไม่ได้ช่วยแก้กรณีการใช้งานนี้โดยเฉพาะเนื่องจากมันยังไม่อนุญาตอินพุต STDIN ที่เหมาะสมจากเชลล์ แต่จำลองอินพุตที่ จำกัดภายใน Emacs เท่านั้น

พื้นหลัง

ฉันต้องการใช้ Babel ของ Org เพื่อเรียนรู้ภาษาการเขียนโปรแกรมใหม่ (Perl และ Bash) โดยใช้บทเรียนจากไฟล์ org หนึ่งไฟล์

ปัญหาคือบทเรียนจำนวนมากพึ่งพา STDIN ตัวอย่างเช่นหากมีการทำงานชิ้นอาหารอันโอชะ Perl ต่อไปนี้:

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

สิ่งเดียวกันโดยใช้ตัวอย่างทุบตี นี้:

#+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 จะรออินพุตในบล็อก tangled ที่กำลังรันอยู่

ถ้าไม่คุณจะกรุณาให้พอยน์เตอร์เกี่ยวกับวิธีการเขียนบางอย่างเช่นtangle-and-run-via-shell-bufferฟังก์ชั่นที่จะ:

  • ยุ่งเหยิงบล็อกรหัสที่จุดบันทึกด้วยชื่อไฟล์ที่กำหนด
  • รันไฟล์ที่เกี่ยวข้องในshellบัฟเฟอร์ที่มองเห็นได้
  • อาจยอมรับอินพุตจากผู้ใช้
  • และในที่สุดก็รายงานSTDOUTหากมีเพื่อ#+RESULTS:?

หากยังไม่มีการใช้งานคุณสมบัติดังกล่าว (ยัง) ใน Org เราจะนำไปใช้กับ elisp ได้อย่างไร


ปรับปรุง: หลังจากการค้นหาและการศึกษาอื่น ๆ คู่มือ Elisp Emacs และดูเหมือนว่าวิธีที่จะทำก็จะได้รับประโยชน์จากCOMINTmake-comint-in-bufferเช่นบางที

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

น่าเสียดายที่ตอนนี้ฉันอยู่เหนือหัวแล้ว😣

คำตอบ:


4

ลองสิ่งนี้

หมายเหตุ : ทำการเปลี่ยนแปลงเล็กน้อยในบล็อกรหัสของคุณ:

  • ย้าย#!/bin/bashเข้าไปในส่วนหัวของการป้องกันรหัสการตั้งค่าโดยอัตโนมัติสิทธิ์ของแฟ้มที่ปฏิบัติการเมื่อบล็อกอีนุงตุงนังเข้า:shebang #!/bin/bashdir-input.sh

  • รหัสแก้ปัญหาเพิ่มให้กับการแสดงที่ได้รับมอบหมายอย่างถูกต้องจาก$TEST_DIRread 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: ")

หัวข้อนี้จะแสดงTest Dir:พร้อมท์ในหน้าต่างเมื่อการป้องกันรหัสจะถูกดำเนินการโดยใช้ minibufferC-c C-c

ป้อนเส้นทางเช่น / path / to / test / dir enter

และบล็อกจะผ่านการป้อนข้อมูลเพื่อผ่าน./dir-input.sh STDINคุณควรเห็นสิ่งต่อไปนี้#+RESULTS:

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

หวังว่าจะช่วย!


รหัสทดสอบด้วย:
GNU Emacs 24.4.1 (x86_64-apple-darwin14.0.0, NS apple-appkit-1343.14) ของปี 2014-12-25 รุ่น
org-mode: 8.3.2


ขอบคุณมากที่ช่วยได้ วิธีที่สร้างสรรค์ในการใช้ vars ให้คำแนะนำอย่างมาก ฉันสงสัยว่าฉันจะไปจับ STDIN "ทั้งหมด" พูดแบบไหนได้บ้างเช่นจากเชลล์ดั้งเดิม? ตัวอย่างเช่นเพื่อให้สามารถอ่านบรรทัดใหม่และตัวอักษรควบคุม (ด้านข้าง CTRL-D)?
gsl

1
@gsl - BTW - ฉันยังคงพยายามหาคำตอบสำหรับคำถามใหม่เกี่ยวกับหลายบรรทัดและอักขระควบคุม หากคุณคิดออกก่อนที่ฉันจะโปรดโพสต์คำตอบของคุณ
Melioratus

ขอบคุณมากสำหรับการเตรียมคำตอบใหม่ ฉันยังคงมองหาวิธีการแก้ปัญหาการทำงาน ฉันคิดไม่ออกด้วยตัวเองยังคงอยู่ในหัวของฉันตอนนี้ ฉันกำลังเลือกคำตอบของคุณและเมื่อไรที่คำตอบใหม่จะเกิดขึ้นให้เลือกในภายหลัง
gsl

สวัสดี @melioratus - คุณสามารถหาวิธีจัดการกับหลายบรรทัดและอักขระควบคุมได้หรือไม่? นั้นจะค่อนข้างมีประโยชน์ในหลาย ๆ กรณี
gsl

1
@gsl - ขอบคุณสำหรับการติดตาม! คุณถูกต้องอ่านจาก stdin จะมีประโยชน์จริงๆและฉันยังคงมอง! ฉันได้ทำการอ่าน stdin เป็นบัฟเฟอร์ชื่อจากบรรทัดคำสั่งแล้วเรียก elisp เพื่ออ่าน multiline buffer เป็นตัวแปร งานนี้เมื่ออ่านจากท่อ แต่น่าเสียดายที่ไม่ได้สำหรับการสตรีมมิ่ง stdin ๆ คือtail file |ทำงาน tail -f file |แต่ไม่ ฉันจะดูบันทึกย่อของฉันและเพิ่มตัวอย่างการทำงานหลายส่วนของฉันเป็นคำตอบใหม่ ขอบคุณสำหรับการเตือน!
Melioratus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.