วิธีทำให้ Emacs อ่านบัฟเฟอร์จาก stdin เมื่อเริ่มต้น?


40

ด้วย Vim ฉันสามารถทำได้อย่างง่ายดาย

$ echo 123 | vim -

เป็นไปได้ที่จะทำอย่างไรกับ 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

เป็นไปไม่ได้ที่จะอ่านบัฟเฟอร์จาก unix pipe หรือไม่?

แก้ไข : เป็นวิธีแก้ปัญหาฉันเขียน shell wrapper ชื่อemacspipe:

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

คำตอบ:


15

ถูกต้องเป็นไปไม่ได้ที่จะอ่านบัฟเฟอร์จาก stdin

การกล่าวถึง stdin เท่านั้นในหน้าข้อมูลของ Emacs คือสิ่งนี้ซึ่งกล่าวว่า:

ในโหมดแบตช์ Emacs จะไม่แสดงข้อความที่ถูกแก้ไขและตัวขัดจังหวะมาตรฐานเทอร์มินัลเช่นC-zและC-cยังคงมีผลตามปกติ ฟังก์ชั่นprin1, princและprint ส่งออกไปstdoutแทนพื้นที่สะท้อนในขณะที่และข้อความผิดพลาดออกไปmessage stderrฟังก์ชั่นที่ปกติแล้วจะอ่านจาก minibuffer จะใช้อินพุตจากstdinแทน

และreadฟังก์ชั่นสามารถอ่านได้stdinแต่เฉพาะในโหมดแบทช์

ดังนั้นคุณไม่สามารถหลีกเลี่ยงปัญหานี้ได้ด้วยการเขียน elisp แบบกำหนดเอง


10
ฉันหมายถึงไม่ดูหมิ่นใครเลย แต่นี่น่ารังเกียจ นี่เป็นคุณสมบัติแก้ไขขั้นพื้นฐานและ GNU EMACS มีมานานหลายทศวรรษแล้ว มันควรจะถูกสร้างขึ้นมา
787832

35

คุณสามารถใช้การทดแทนกระบวนการ :

$ emacs --insert <(echo 123)

นี่เป็นคำตอบที่ใกล้เคียงกับฟังก์ชั่น Vim มากที่สุด สวยมากแค่ย้ายส่วน piped ลงในการทดแทน subprocess
dbmikus

@ dbmikus ฉันไม่สามารถตัดสินใจได้ว่าฉันจะชอบแบบไหนระหว่าง Mine กับ Tomasz Obrębski's ..
Andrew Wood

ผลลัพธ์ของ Tomasz ทำให้ฉันได้รับข้อผิดพลาดดังต่อไปนี้ด้วยเหตุผลบางอย่าง: emacs: standard input is not a tty
dbmikus

โอ้จริง ๆ ! ฉันคิดว่าเขาจะทดสอบก่อนโพสต์
Andrew Wood

1
อาจขึ้นอยู่กับเดือนนั้น ๆ
dbmikus

14

คุณสามารถเปลี่ยนเส้นทางไปยังไฟล์จากนั้นเปิดไฟล์ เช่น

echo 123 > temp; emacs temp

jweede ตั้งข้อสังเกตว่าถ้าคุณต้องการให้ไฟล์ชั่วคราวถูกลบโดยอัตโนมัติคุณสามารถ:

echo 123 > temp; emacs temp; rm temp

วิธี Emacsy ที่จะทำคือการเรียกใช้คำสั่งของเชลล์ใน Emacs

M-! echo 123 RET

ที่ให้บัฟเฟอร์ชื่อ * Shell Command Output * พร้อมผลลัพธ์ของคำสั่ง


ใช่ฉันรู้ว่ามีวิธี emacsy แต่ฉันหวังว่ามันอาจจะใช้วิธี unixy การสร้างไฟล์ชั่วคราวไม่ใช่ตัวเลือกที่ดีมาก (ฉันต้องจำไว้ว่าต้องลบมันในภายหลัง)
sastanin

1
เช่น:echo 123 > temp; emacs temp; rm temp
jweede

2
โดยทั่วไปมีความต้านทานสูงระหว่าง Emacs และ Unix หรืออย่างน้อยระหว่าง Emacs และกระบวนการทำงาน Unix แบบดั้งเดิม
Richard Hoskins

2
@jweede หากคุณต้องการเพิ่ม M-! ส่วนหนึ่งของคำตอบของฉันกับคุณจากนั้นฉันสามารถลบคำตอบของฉัน คำตอบของเรามีการทับซ้อนกันมาก แต่ฉันคิดว่าเมตา - แบงเป็นสิ่งสำคัญสำหรับผู้อ่านในอนาคต
Richard Hoskins

1
temp อาจมีอยู่แล้วในไดเรกทอรีปัจจุบันมันไม่ปลอดภัย TMP=$(mktemp) && cat > $TMP && emacs23 $TMP ; rm $TMPเป็นวิธีแก้ปัญหาผมเขียนกระดาษห่อ: ขอบคุณทุกๆคน!
sastanin

9

เป็นไปได้ดูhttps://stackoverflow.com/questions/2879746/idomatic-batch-processing-of-text-in-emacs

นี่คือเสียงสะท้อนในสคริปต์ emacs (คัดลอกจากลิงค์ด้านบน):

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

หรืออ่านมันลงในบัฟเฟอร์แล้วพิมพ์มันทั้งหมดในครั้งเดียว

#!/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

เป็นไปได้ที่จะสร้างฟังก์ชั่นเชลล์อย่างง่ายซึ่งทำงานได้เหมือนที่อ่านจาก stdin (แม้ว่าอันที่จริงแล้วมันกำลังเขียนไปยังไฟล์ชั่วคราวแล้วก็อ่านมัน) นี่คือรหัสที่ฉันใช้:

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

คุณเพียงใช้ฟังก์ชั่นเป็นนามแฝงสำหรับ emacs เช่น

echo "hello world" | e -

หรือตามปกติจากไฟล์

e hello_world.txt

แทนที่emacsด้วยemacsclientในฟังก์ชั่นการทำงานเช่นกัน


สิ่งนี้ทำงานได้ดีสำหรับฉัน แต่ _emacsfun ควรเป็นemacsclient -c -t $@หรืออย่างน้อยก็ปล่อย -n ตัวเลือก man pages with emacsclient -t --eval "(man \"$1\")" --eval "(delete-window)" (และตอนนี้คุณสามารถhelm-swoopไปสู่ ​​Man Glory!)
Alejandro

1
นี่เป็นคำตอบเดียวที่ฉันจะได้ทำงานกับ emacsclient ฉันสร้างเชลล์สคริปต์จากแนวคิดพื้นฐานเพื่อให้ฉันสามารถเรียกได้จากการตั้งค่าของ i3 +1
ergosys

6

งานนี้:

echo 123 | emacs --insert <(cat)

แต่ด้วยเหตุผลบางอย่างเฉพาะกับ emacs โหมดกราฟิก (Gnome, Konsole, GNU Emacs 23.4.1) คำสั่ง:

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

สร้างข้อผิดพลาด 'emacs: อินพุตมาตรฐานไม่ใช่ tty' ข้อผิดพลาดเดียวกันปรากฏขึ้นเมื่อพยายามในคอนโซลข้อความดิบ


echo 123 | exec emacs -nw --insert <(cat) </dev/ttyควรทำงาน.
pyrocrasty

ใช้งานได้; ทำไมผู้บริหาร สิ่งนี้ยังใช้งานได้: emacs -nw --insert <(echo 123) </ dev / tty
RoyM

รูปที่ไป: ใช้งานได้อย่างสวยงามบน Emacs (w32) บน Cygwin ที่การตั้งค่าอื่น ๆ ของฉันทำไม่ได้
Charles Roberto Canato

5

ความเป็นไปได้อื่น ๆ ที่ไม่ได้กล่าวถึงในคำตอบก่อนหน้านี้คือการใช้/dev/stdinถ้าตัวแปร Unix ที่คุณเลือกมี

ก็พยายามที่จะเปิด/dev/stdinโดยตรงไม่ทำงานเพราะ Emacs Symbolic link that points to nonexistent fileไม่ได้ตรวจสอบแล้วไม่กี่รายงาน (และหาก Emacs อนุญาตให้คุณโหลดไฟล์ได้ให้ลองบันทึกอีกครั้งเพราะ/dev/stdinไม่ค่อยทำสิ่งที่ผู้ใช้คาดหวัง)

อย่างไรก็ตามการรวม/dev/stdinกับ--insertอาร์กิวเมนต์จะทำงาน:

echo 123 | emacs --insert /dev/stdin

มันควรจะตั้งข้อสังเกตว่ารุ่นนี้จะทำงานเฉพาะเมื่อใช้ X. หากคุณต้องแก้ปัญหาที่ทำงานใน terminal ผมขอแนะนำให้คุณมองไปที่คำตอบอื่น


ฉันได้รับemacs: standard input is not a ttyข้อความทดสอบบน linux และ bsd

1
@ Chinggis6 ดูเหมือนว่าคำแนะนำของฉันจะใช้ได้เฉพาะเมื่อใช้ X11 ถ้าฉันพิมพ์ครั้งแรกunset DISPLAYฉันจะได้รับข้อความแสดงข้อผิดพลาดเช่นเดียวกับคุณ
kasperd

1
@ Chinggis6 ฉันได้อัปเดตคำตอบของฉันเพื่อชี้ให้เห็นว่ามันต้องการ X ในการทำงานและชี้ไปที่คำตอบที่ใช้ได้โดยไม่ต้อง X
kasperd

2

offhand บางสิ่งบางอย่างที่ชอบ:

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

หรือ

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

เป็นตัวเลือก Emacs ไม่ได้รวมเข้ากับ UNIX อย่างที่ vim ทำ


1
เป็นที่น่าแปลกใจที่ Emacs ไม่ได้รวมกับ UNIX ได้ดีขึ้นเนื่องจากประวัติศาสตร์และหนึ่งในหลักสำคัญของ UNIX ก็คือ "ทุกอย่างเป็นไฟล์" มันให้ความรู้สึกเป็นธรรมชาติในการส่งออกท่อไปยัง Emacs โดยตรง
SabreWolfy

5
@ SabreWolfy ในขณะที่ GNU Emacs เป็นโฮสต์ส่วนใหญ่ใน Unix แต่ไม่ใช่ "โปรแกรม Unix" ในแบบที่ Vim เป็น แต่เป็นเครื่อง Lisp ที่ใช้ตัวแก้ไขข้อความที่ไม่ขึ้นอยู่กับแพลตฟอร์ม (ดูคำตอบของ Richard Hoskins; "วิธีการของ Emacs" ในการทำเช่นนี้ไม่ใช่เพื่อไพพ์คำสั่งเชลล์ไปยัง Emacs แต่ต้องเรียกใช้คำสั่งเชลล์จากภายใน Emacs ผ่านM-!ซึ่งจะบันทึกผลลัพธ์ที่ได้ลงในบัฟเฟอร์ชั่วคราวโดยอัตโนมัติ) Holy สงครามกันบรรณาธิการไม่ "ดีกว่า" กว่าคนอื่น; พวกเขามีมุมมองที่แตกต่างกันมากในทุกสิ่ง
Aaron Miller

ยกเว้นตอนที่คุณอยู่ในเปลือกและต้องการทำบางสิ่งเช่นcurl foo.bar | vim -.. ฉันขอโทษ ฉันหมายถึงcurl foo.bar | emacsยกเว้นคุณไม่สามารถทำเช่นนั้นได้
dylnmc
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.