โปรแกรมส่งออกไปยังที่อื่นนอกเหนือจาก STDOUT / STDERR อย่างไร จะหลีกเลี่ยงได้อย่างไร


15

เห็นได้ชัดว่าฉันไม่ทราบปลายทางปลายทางทั้งหมดที่พร้อมใช้งาน ฉันรู้เกี่ยวกับstdout( &1) และstderr( &2) อย่างไรก็ตามหลังจากเปลี่ยนเส้นทางทั้งสองอธิบายบางครั้งฉันยังคงได้รับผลลัพธ์บางอย่างในคอนโซลของฉัน!

ตัวอย่างที่ง่ายที่สุดที่ฉันนึกได้ก็คือ GNU Parallel ทุกครั้งที่ฉันใช้มันฉันเห็นประกาศการอ้างอิง แม้เมื่อฉันทำ&2>1 > fileฉันก็ยังเห็นประกาศ

และเช่นเดียวกับemerge: เมื่อฉันวิ่งออกมาและมีปัญหาบางอย่างข้อมูลบางอย่างจะไม่ถูกพิมพ์ออกไปstdoutหรือstdinเนื่องจากฉันเปลี่ยนเส้นทางพวกเขาและพวกเขายังคงผ่าน

ฉันใช้วิธีแก้ปัญหาเหล่านี้เป็นส่วนใหญ่scriptแต่ฉันก็ยังสงสัยว่าอะไรทำให้เกิดปัญหานี้


1
โปรดระบุตัวอย่างเต็มรูปแบบ
Kusalananda

เปลือกไหน ดูที่mywiki.wooledge.org/BashFAQ/055และstackoverflow.com/questions/876239/…
Sundeep

8
คุณจะไม่ได้รับพวกเขาทั้งหมด /dev/ttyสคริปต์สามารถเขียนถึง
Satō Katsura

1
สำหรับ GNU parallel: mkdir ~/.parallel; touch ~/.parallel/will-citeจะปิดการใช้งานข้อความที่น่ารำคาญ อีกวิธีหนึ่งคือมองไปรอบ ๆ สำหรับการใช้งานอื่น ๆ parallelของ
Satō Katsura

2
@OleTange เพราะมันไม่ใช่ปัญหา - ฉันถามว่าทำไมมีอะไรบางอย่างเกิดขึ้นและฉันใช้parallelเป็นตัวอย่าง
MatthewRock

คำตอบ:


40

ไวยากรณ์ที่คุณใช้ผิด

cmd &2>1 >file

จะถูกแยกย่อยเป็น

cmd &
2>1 >file

นี่จะ:

  1. เรียกใช้cmdเป็นงานพื้นหลังโดยไม่มีการเปลี่ยนเส้นทาง
  2. ในกระบวนการที่แยกต่างหาก (ไม่มีคำสั่ง!) จะเปลี่ยนเส้นทางstderrไปยังไฟล์ที่เรียกว่าแท้จริง1และเปลี่ยนเส้นทางstdoutไปfile

ไวยากรณ์ที่คุณต้องการคือ:

cmd >file 2>&1

คำสั่งของการดำเนินการเป็นสิ่งสำคัญ นี่จะ:

  1. เปลี่ยนเส้นทางstdoutไปที่file
  2. เปลี่ยนเส้นทางstderrไปที่&1- เช่น filehandle เดียวกับstdout

ผลที่ได้คือว่าทั้งสองstderrและจะถูกนำไปstdoutfile

ในbashรูปแบบที่ไม่ได้มาตรฐานที่เรียบง่ายกว่า (และดังนั้นฉันจึงไม่แนะนำให้ใช้ในบริเวณที่พกพาได้) ไวยากรณ์ของการcmd &> fileทำสิ่งเดียวกัน


ขอบคุณมาก ปัญหาอื่นอาจเป็นไปได้/dev/ttyแต่หวังว่าสิ่งนี้จะไม่เกิดขึ้นบ่อยเกินไป (ถ้าเลย)
MatthewRock

5
หากคุณมีatคำสั่งบนเครื่องและมีสิทธิ์ใช้งานคุณสามารถเรียกใช้คำสั่งผ่านat nowได้ ดู manpage สำหรับรายละเอียด สิ่งนี้จะรันคำสั่งผ่านกลไกกระบวนการแบทช์และกระบวนการจะไม่มี tty ให้เขียน แต่โดยทั่วไปฉันไม่ต้องกังวลเกี่ยวกับกรณีขอบนี้ โดยปกติเพียง /dev/ttyแต่กระบวนการที่ต้องมีปฏิสัมพันธ์และจงใจต้องสิ่งที่จอแสดงผลกับผู้ใช้งานแม้จะมีการเปลี่ยนเส้นทางจะใช้
Stephen Harris

เคยไปทำแบบนั้นแล้ว
davidbak

10

มีสองปัญหา

/dev/ttyคนแรกคือว่าคำสั่งเรื่องที่สองคือ

ลองใช้สคริปต์นี้เป็นสคริปต์ตัวอย่างที่เราต้องการจับภาพผลลัพธ์จาก:

test.sh:

#!/bin/bash

echo dada
echo edada 1>&2
echo ttdada >/dev/tty

ตอนนี้เรามาดูผลลัพธ์ของคำสั่ง:

./testmyscript.sh 2>&1 >/dev/null:

edada
ttdada

เนื่องจากลำดับของการประเมินผลจากซ้ายไปขวาอันดับแรกเราจะได้รับ "เปลี่ยนเส้นทางstderrไปยังที่ใดก็ตามที่stdoutกำลังแสดงผล (ดังนั้นเอาต์พุตคอนโซล)" จากนั้นเราจะได้ "เปลี่ยนเส้นทางstdoutไปที่/dev/nullเราจบลงด้วยสถานการณ์เช่นนี้:

stdout-> /dev/null stderr-> คอนโซล

ดังนั้นเราทำให้ถูกต้อง:

./testmyscript.sh >/dev/null 2>&1

และเราได้รับ:

ttdada.

ตอนนี้เราทำ "เปลี่ยนเส้นทางstdoutไปยัง/dev/null" แล้ว "เปลี่ยนเส้นทาง stderr ไปยังตำแหน่งที่ stdout ชี้" (ดังนั้น, /dev/null) เย่!

อย่างไรก็ตามเรายังมีปัญหาอยู่ /dev/ttyพิมพ์โปรแกรม ตอนนี้ฉันไม่ทราบวิธีแก้ไขพฤติกรรมเช่นนี้ดังนั้นคุณน่าจะต้องการมากที่สุดscriptแต่หวังว่าพฤติกรรมนี้จะไม่เกิดขึ้นบ่อยเกินไป

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