เหตุใดผลลัพธ์ของบางโปรแกรมของ Linux จึงไม่ใช่ทั้ง STDOUT และ STDERR


21

เหตุใดผลลัพธ์ของบางโปรแกรมของ Linux จึงไม่ใช่ทั้ง STDOUT และ STDERR

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

ตัวอย่างคือคำสั่ง 'เวลา':

time sleep 1 2>&1 > /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

หรือ

time sleep 1 &> /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

เหตุใดฉันจึงเห็นเอาต์พุตทั้งสองครั้ง ผมคาดว่ามันทุกคนที่จะได้รับการประปาเข้า/ dev / null

สตรีมเอาต์พุตใดที่ใช้เวลาและฉันจะไพพ์ลงในไฟล์ได้อย่างไร

วิธีหนึ่งในการแก้ไขปัญหาคือสร้างสคริปต์Bashตัวอย่างเช่นcombine.shบรรจุคำสั่งนี้:

$@ 2>&1

จากนั้นสามารถบันทึกเอาต์พุตของ 'เวลา' ในวิธีที่ถูกต้อง:

combine.sh time sleep 1 &> /dev/null

(ไม่เห็นเอาต์พุต - ถูกต้อง)

มีวิธีในการบรรลุสิ่งที่ฉันต้องการโดยไม่ใช้สคริปต์การรวมที่แยกต่างหากหรือไม่


3
ก่อนอื่นคุณควรกลับคำสั่ง: 2>&1 > /dev/nullหมายถึง "2 ตอนนี้ไปที่ที่ 1 ไป (เช่น terminal โดยปริยาย) จากนั้น 1 ไปที่ / dev / null (แต่ 2 ยังไปที่ terminal!) ใช้>/dev/null 2>&1เพื่อบอกว่า "1 ไปที่ / dev / null จากนั้น 2 ไปที่ 1 ไป (เช่นไปยัง / dev / null) สิ่งนี้ยังคงไม่ทำงานที่นี่เนื่องจาก 'เวลา' ในตัวจะไม่ถูกเปลี่ยนเส้นทาง แต่โดยทั่วไปจะถูกต้องมากกว่า (ตัวอย่างเช่นจะใช้งานได้หากคุณใช้ / usr / bin / time) คิดเกี่ยวกับ "2> & 1" เป็นการคัดลอก "ทิศทาง" ของ 1 ลงใน 2 ไม่ใช่ 2 ไปที่ 1
Olivier Dulac

คำตอบ:


38

คำถามนี้เป็นคำถามแก้ไขในBashFAQ / 032 ในตัวอย่างของคุณคุณจะ:

{ time sleep 1; } 2> /dev/null

เหตุผลว่าทำไม

time sleep 1 2>/dev/null

ไม่ประพฤติวิธีการที่คุณคาดหวังว่าเป็นเพราะมีไวยากรณ์ที่คุณจะต้องการtimeคำสั่งsleep 1 2>/dev/null(ใช่คำสั่งsleep 1กับstderrเปลี่ยนเส้นทางไป/dev/null) builtin timeทำงานในลักษณะนั้นเพื่อทำให้สิ่งนี้เป็นจริงได้

bash builtinจริงสามารถทำเช่นนี้เพราะ ... ดีก็ builtin พฤติกรรมดังกล่าวจะเป็นไปไม่ได้ด้วยคำสั่งภายนอกมักจะอยู่ในtime /usr/binอันที่จริง:

$ /usr/bin/time sleep 1 2>/dev/null
$

ตอนนี้คำตอบสำหรับคำถามของคุณ

เหตุใดผลลัพธ์ของบางโปรแกรมของ linux จึงไม่ใช่ทั้ง STDOUT และ STDERR

คือมันไม่ออกไปstdoutหรือstderr

หวังว่านี่จะช่วยได้!


2
คุณสามารถสร้าง FD อื่น ๆ และมีคำสั่ง explicitely ไปที่เหล่านั้น (เช่นในสคริปต์ทุบตี: exec 3>/some/file ; ls >&3 ;)
โอลิเวีย Dulac

@ OlivierDulac แน่นอนหรือแม้กระทั่งง่ายกว่ากับcoprocbuiltin แต่มันไม่ใช่กรณีสำหรับtimebuiltin
gniourf_gniourf

@ gniourf-gniourf: ฉันแสดงความคิดเห็นเพราะประโยคของคุณ "ผลลัพธ์ไปที่ stdout หรือ stderr" ^^
Olivier Dulac

14

โดยเฉพาะอย่างยิ่งคำถามของคุณเกี่ยวกับtimebuiltin ได้รับการตอบรับ แต่มีมีคำสั่งบางอย่างที่ไม่ได้เขียนอย่างใดอย่างหนึ่งหรือstdout ตัวอย่างคลาสสิกเป็นคำสั่ง stderr Unix มีข้อโต้แย้งไม่เข้ารหัสเข้ามาตรฐานและเขียนมันออกมาตรฐาน มันแจ้งให้ผู้ใช้รหัสผ่านโดยใช้ซึ่งโดยค่าเริ่มต้นเอาท์พุทแจ้งให้ เป็นอุปกรณ์ปลายทางในปัจจุบัน การเขียนเพื่อให้มีผลในการเขียนไปยังเทอร์มินัลปัจจุบัน (ถ้ามีให้ดูที่)cryptcryptstdinstdoutgetpass()/dev/tty/dev/tty/dev/ttyisatty()

เหตุผลที่cryptไม่สามารถเขียนเป็นเพราะมันเขียนเข้ารหัสส่งออกไปยังstdout stdoutนอกจากนี้ยังเป็นการดีกว่าถ้าให้พร้อมที่จะ/dev/ttyเขียนแทนstderrเพื่อที่ว่าหากผู้ใช้เปลี่ยนเส้นทางstdoutและstderrจะยังคงเห็นพรอมต์ (ด้วยเหตุผลเดียวกันcryptไม่สามารถอ่านรหัสผ่านได้stdinเนื่องจากใช้เพื่ออ่านข้อมูลเพื่อเข้ารหัส)


2
+1 มีความเกี่ยวข้องน้อยกว่าสำหรับ OP แต่มีความเกี่ยวข้องมากขึ้นสำหรับทุกคนที่เจอ "ทำไมผลลัพธ์ของลินุกซ์บางโปรแกรมจึงไม่ใช่ทั้ง STDOUT และ STDERR?" ผ่าน Google :-)
ruakh

0

time sleep 1 > /dev/null 2>&1# การเปลี่ยนเส้นทางเอาต์พุต "sleep's" do null จากนั้น "เวลา" จะเขียนเอาต์พุตของตัวเองโดยไม่มีการเปลี่ยนเส้นทาง มันก็เหมือน " time (sleep 1 > /dev/null 2>&1)"

(time sleep 1) > /dev/null 2>&1 # run "time sleep 1" จากนั้นเปลี่ยนเส้นทางเอาต์พุตเป็น null

[] s


-1

ปัญหาในกรณีของคุณคือการเปลี่ยนเส้นทางทำงานได้ในอีกทางหนึ่ง คุณเขียน

time sleep 1 2>&1 > /dev/null

สิ่งนี้จะเปลี่ยนเส้นทางเอาต์พุตมาตรฐานไปยัง/dev/nullและจากนั้นเปลี่ยนเส้นทางข้อผิดพลาดมาตรฐานไปยังเอาต์พุตมาตรฐาน

ในการเปลี่ยนเส้นทางเอาต์พุตทั้งหมดที่คุณต้องเขียน

time sleep 1 > /dev/null 2>&1 

แล้วข้อผิดพลาดมาตรฐานจะถูกนำไปออกมาตรฐานและหลังจากนั้นทั้งหมดออกมาตรฐาน (ที่มีข้อผิดพลาดมาตรฐาน) /dev/nullจะถูกนำไป


นี้ไม่ได้ทำงานกับทุบตีในตัว timeดูคำตอบของฉันสำหรับคำอธิบายบางอย่าง
gniourf_gniourf

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