zsh ไม่สามารถอินพุตไปยังเทอร์มินัลเมื่อวาง stdin และ stdout ด้วยคำสั่งตัวแปรที่มีเอาต์พุต tty


11

ข้อมูลระบบ:

macOS Sierra 10.12.6
zsh 5.4.2 (x86_64-apple-darwin16.7.0)
GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.3.0)

เลื่อนไปที่ตัวอย่างที่ด้านล่างหากคุณเพียงต้องการขุดตัวอย่างง่าย ๆ ที่ฉันทำ

หมายเหตุ: ฉันไม่ใช่zshผู้ใช้ที่ยิ่งใหญ่


ฉันกำลังมองหาfzfปุ่มลัดสำหรับbashและzsh.

$(__fzfcmd)แจ้งให้ทราบว่าพวกเขาทั้งสองเรียกใช้คำสั่งตัวแปร __fzfcmdโดยเอาต์พุตดีฟอลต์fzfไปยัง stdout และการแทนที่พารามิเตอร์เพิ่งรัน command ( fzf) ซึ่งเป็นผลมาจากเอาต์พุต

หนึ่งความแตกต่างระหว่างbashและzshสคริปต์เป็นที่bashหนึ่งต่อท่อส่งออกของ$(__fzfcmd)แต่zshเพียงแค่จับมันไว้ภายในอาร์เรย์ ฉันเดาว่าเป็นเพราะปัญหาzshเมื่อคุณไปป์ไลน์เอาท์พุทของfzfที่คุณไม่สามารถป้อนข้อมูลfzfและกระบวนการไพพ์ไปยังโดยfzfไม่ได้รับ stdin ใด ๆ ทางเลือกเดียวของคุณคือการหรือ^Z ดูเหมือนจะเป็นพื้นหลังกระบวนการด้วยเหตุผลบางอย่าง หรือบางทีพวกเขาแค่ต้องการแถวลำดับเพื่อที่จะได้วิ่งต่อไป รุ่นไม่มายากลบางอย่างในกุญแจสำคัญที่มีผลผูกพันกับ^C^Czle vi-fetch-historybash"\e^": history-expand-line

ตอนนี้fzfไม่สำคัญ ดูเหมือนว่าคุณเพียงแค่ต้องใช้โปรแกรมที่ให้ผลลัพธ์ที่ttyจะเรียกโดยการทดแทนพารามิเตอร์เพื่อทำให้เกิดปัญหานี้ ดังนั้นฉันจะแสดงตัวอย่างที่ง่ายขึ้น

ต่อไปนี้เป็นคำสั่งอื่น ๆ ที่ให้ผลลัพธ์ttyซึ่งอาจทำให้เกิดปัญหานี้ได้zsh:

  • vipe (เรียกใช้เครื่องมือแก้ไขกลางท่อ)
  • 'vim -' (ทำให้เป็นกลุ่มอ่านจาก stdin คล้ายกับ vipe แต่จะไม่ส่งออกไปยัง stdout)

ในตัวอย่างด้านล่างแทนการเกิดขึ้นของทุกคนvipeด้วยvim -ถ้าคุณไม่ต้องการที่จะทำแยกติดตั้ง เพียงจำไว้ว่าvim -จะไม่ส่งออกเนื้อหาตัวแก้ไขไปยัง stdout เช่นvipeนั้น

ตัวอย่าง:

1) echo 1 | vipe | cat            # works in both bash and zsh
2) echo 1 | $(echo vipe) | cat    # works in bash only. zsh problem with no output until I hit `^C`:
   ^C
   zsh: done                    echo 1 | 
   zsh: suspended (tty output)  $(echo vipe) | 
   zsh: interrupt               cat
   # seems like the process is backgrounded. I can still see it in jobs command

3) cat <(echo 1 | $(echo vipe))   # zsh and bash has the problem. I'm guessing because
                                  # the file isn't finished writing and cat is
                                  # blocking vipe's tty output
                                  # both their `^C` output is just:
   ^C # nothing special, as expected

4) cat < <(echo 1 | $(echo vipe)) # works in both bash and zsh
5) echo 1 | $(echo vipe) > >(cat) # works in both bash and zsh

# The following don't have and input pipe to vipe.
# Type something then send EOF with ^D
6) vipe | cat                     # works for both
7) $(echo vipe) | cat             # works for both

ตอนนี้ผมสงสัยว่าทำไมส่วนใหญ่2)มีปัญหาสำหรับzshแต่ไม่bashและทำไม4)และแก้ไขปัญหาให้5)zsh

ข้อกำหนดสำหรับzshการมีปัญหานี้ดูเหมือนจะเป็นสิ่งที่ฉันใส่ในชื่อ:

  • ท่ออินพุต
  • รันคำสั่งโดยการทดแทนตัวแปร / พารามิเตอร์ที่มีttyเอาต์พุต
  • ท่อส่งออก

UPDATE

ฉันได้เพิ่มวิธีแก้ไขอื่นที่ไม่ทำให้เกิดzshปัญหานี้, 5). มันคล้ายกับ4)แต่แทนที่จะเปลี่ยนเส้นทางstdoutโดยตรงไปยังstinฉันเปลี่ยนเส้นทางมันเป็นไฟล์ที่เปลี่ยนเส้นทางไปstdinใช้การทดแทนกระบวนการ


1
ดังที่ผลลัพธ์ของpsจะบอกคุณในกรณีเหล่านี้ไม่มีเปลือกหอยที่แช่แข็งหรือติดอยู่ พวกเขากำลังรอกระบวนการของเด็กในวิธีปกติ และพวกเขาจะวนกลับไปที่พร้อมท์สำหรับการป้อนข้อมูลในวิธีปกติเมื่อกระบวนการลูกเหล่านั้นถูกระงับหรือยกเลิก ชื่อคำถามและเนื้อความของคุณรวมถึงหลักฐานเท็จโดยนัย "ทำไมเปลือกของฉันถึงแข็ง?" เป็นคำถามที่โหลดไม่ได้คำตอบเมื่อเปลือกของคุณไม่ได้แช่แข็งในตอนแรก คุณจะมีคำถามที่ดีกว่าสำหรับการลบหลักฐานเท็จโดยนัยนี้
JdeBP

ตกลงฉันสามารถเปลี่ยนได้ มันไม่ได้แช่แข็งในแง่ที่ว่ากระบวนการไม่สามารถเรียกใช้คำสั่งบน CPU ได้อีกต่อไป คุณถูกต้องว่ามันกำลังรอ แต่มันไม่ 'ติด' ใช่ไหม กำลังรออินพุตที่ฉันไม่สามารถให้ได้ เป็นคำที่ดีกว่าที่จะอธิบายสั้นกระชับนี้คืออะไร? ไม่ตรงกับคำอธิบายของhang when either a computer program or system ceases to respond to inputs
dosentmatter

1
เชลล์ไม่รออินพุต มันกำลังรอลูกอยู่ คำถามนี้จะดีกว่าใส่เพียงแค่อธิบายสิ่งที่เกิดขึ้น อย่าตั้งสมมติฐานและการอนุมานเช่น "เปลือกหอยของฉันแข็ง" แล้วถามเกี่ยวกับการอนุมาน อธิบายว่าเกิดอะไรขึ้นและถามเกี่ยวกับสิ่งนั้น: ลำดับของอินพุตเทอร์มินัลอักขระพิเศษ (ซึ่งโดยปกติจะระงับงานด้านหน้าหรือขัดจังหวะหรือออกจากงานหรือส่ง EOF ไปยังกระบวนการอ่านจากเทอร์มินัล) ไม่มีผล เกิดอะไรขึ้น? ทำไม? . สิ่งนี้สามารถจำลองได้บน Debian Linux และ FreeBSD / TrueOS โดยวิธีการ,
JdeBP

1
ฉันได้รายงานข้อผิดพลาดเกี่ยวกับการพัฒนา zsh รายการทางไปรษณีย์ สำหรับตอนนี้คุณควรจะสามารถหลีกเลี่ยงได้ด้วยการห่อมันลงในชั้นย่อย(echo | $(echo vipe) | cat)
Stéphane Chazelas

1
ความจริงที่ว่ากระบวนการทดแทนเริ่มต้นในพื้นหลังเป็นเอกสารฉันคิดว่า (หรือที่รู้จักกันอย่างน้อย)
Stéphane Chazelas

คำตอบ:


0

เราเชื่อว่าปัญหาของคุณทวีความรุนแรงเกินคาดเพื่อขยายส่วนขยายของคุณอย่างไม่เหมาะสม

การอ้างอิงจากzsh: 14 ส่วนขยาย

คำสั่งที่อยู่ในวงเล็บนำหน้าด้วยเครื่องหมายดอลลาร์เช่น $(...)หรือยกมาด้วยเครื่องหมายเน้นเสียงที่รุนแรงเช่น ' ...' จะถูกแทนที่ด้วยเอาต์พุตมาตรฐานโดยลบบรรทัดใหม่ต่อท้าย หากการทดแทนไม่ได้อยู่ในเครื่องหมายคำพูดคู่เอาต์พุตจะแตกเป็นคำโดยใช้พารามิเตอร์ IFS การเปลี่ยนตัวผู้เล่น$(cat foo)อาจถูกแทนที่ด้วยเทียบเท่า $(<foo)แต่ได้เร็วขึ้น ในทั้งสองกรณีหากตั้งค่าตัวเลือก GLOB_SUBST เอาต์พุตจะมีสิทธิ์สร้างชื่อไฟล์

โปรดทราบว่าตัวอย่าง # 2 ในคำถามของคุณให้ผลลัพธ์ที่ไม่สิ้นสุดของ NULL เนื่องจาก:

หากการทดแทนไม่ได้อยู่ในเครื่องหมายคำพูดคู่เอาต์พุตจะแตกเป็นคำโดยใช้พารามิเตอร์ IFS

กล่าวอีกนัยหนึ่งเชลล์รออย่างไม่สิ้นสุดechoเนื่องจากตัวคั่นเริ่มต้นคือ SPACE เสียงสะท้อนจะไม่เสร็จสมบูรณ์ ดู TLDP: ตัวแปรภายใน สิ่งนี้จะทำให้ท่อค้างสำหรับcatคำสั่ง

ในฐานะที่เป็นลางสังหรณ์ฉันเชื่อว่า 4 และ 5 งานเนื่องจากการเปลี่ยนเส้นทางออก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.