ฉันจะระงับเอาต์พุตได้อย่างไรถ้าคำสั่งสำเร็จ


22

ฉันต้องการทำให้เอาต์พุตของสคริปต์ง่ายขึ้นโดยระงับเอาต์พุตของคำสั่งรองที่มักจะประสบความสำเร็จ

อย่างไรก็ตามการใช้-qมันซ่อนเอาท์พุทเมื่อมันล้มเหลวเป็นครั้งคราวดังนั้นฉันจึงไม่มีทางเข้าใจข้อผิดพลาด stderrนอกจากนี้คำสั่งเหล่านี้เข้าสู่ระบบการส่งออกของพวกเขาใน

มีวิธีระงับเอาต์พุตของคำสั่งเฉพาะเมื่อสำเร็จหรือไม่?

ตัวอย่างเช่น (แต่ไม่ จำกัด เฉพาะ) สิ่งเช่นนี้:

mycommand | fingerscrossed

หากทุกอย่างเป็นไปด้วยดีfingerscrossedจับเอาท์พุทและทิ้งมันไป มิฉะนั้นจะส่งกลับไปยังเอาต์พุตมาตรฐานหรือข้อผิดพลาด (อะไรก็ตาม)

คำตอบ:


36

moreutils' chronicคำสั่งไม่เพียงแค่นั้น:

chronic mycommand

จะกลืนmycommandเอาท์พุทของมันเว้นเสีย แต่จะล้มเหลวซึ่งในกรณีที่เอาท์พุทปรากฏขึ้น


1
ขอขอบคุณ. ฉันคิดว่ามันไม่ได้ติดตั้งไว้ในระบบปฏิบัติการ Unix ส่วนใหญ่ใช่ไหม
Matthieu Napoli

1
อาจจะไม่ถึงแม้ว่ามันจะเป็นแพคเกจที่กว้างขวางดังนั้นจึงควรติดตั้งง่าย
สตีเฟ่น Kitt

1
Debian moreutilsมีมันในแพคเกจ ดีสำหรับฉันแล้ว :)
Tom Zych

6
โปรดทราบว่าจะเก็บเอาต์พุตทั้งหมดในหน่วยความจำ
Stéphane Chazelas

1
@ StéphaneChazelasที่น่าจะเป็นวิธีเดียวที่จะใช้สิ่งนี้การส่งออกจะต้องเก็บไว้ในขณะที่คำสั่งทำงานในกรณีที่มีความจำเป็น
Centimane

11
### do this bit once at the top of your script
divert=
exec 3<>"${divert:=$(mktmp)}" 4<>/dev/null
rm -- "$divert"; unset divert
### then do this bit as often as needed
command >&3 2>&3
cat <&3 >&"$(((RTN=$?)?2:4))"

นั่นน่าจะเป็นการหลอกลวง มันจะบัฟเฟอร์เอาต์พุตของแต่ละcommandไฟล์ลงในไฟล์ชั่วคราวที่ถูกลบและหลังจากนั้นกาลักน้ำเอาต์พุตของมันจะเป็นอย่างใดอย่างหนึ่ง/dev/nullหรือ stderr ขึ้นอยู่กับว่าสถานะการส่งคืนของมันไม่เป็นศูนย์หรือไม่ เพราะไฟล์ temp จะถูกลบออกไปข้างหน้าของเวลาที่ไม่สามารถอ่านได้โดยกระบวนการใด ๆ แต่เปลือกปัจจุบันและเด็กที่บ่งไฟล์(ยกเว้นส่อเสียด/proc/$pid/fdสอดแนมที่มีสิทธิ์ที่เหมาะสม)และมันไม่จำเป็นต้องมีการทำความสะอาดเมื่อคุณกำลังผ่าน

อาจเป็นวิธีที่สะดวกกว่าในระบบ linux:

divert(){
    "$@" >&3 2>&3 ||
    eval "cat <&3
          return $?"
}   3<<"" 3<>/dev/fd/3

... ซึ่งในเปลือกหอยส่วนใหญ่ทำงานเหมือนคนอื่น ๆ divert some simple-command with argsยกเว้นว่าคุณสามารถเรียกมันเช่น: ระวังของคำสั่งที่ผลผลิตสูงใน"$@"แต่สำหรับdash, yashหรือบางหอยอื่น ๆ ที่ทำที่นี่เอกสารที่มีท่อ - ฉันคิดว่ามันอาจจะเป็นไปได้ในเปลือกหอยเหล่านั้นเพื่อกรอกบัฟเฟอร์ท่อ(ที่เริ่มต้นของรอบ 128KB บน Linuxes ก)และเพื่อให้การหยุดชะงัก . ที่ไม่ควรจะเป็นกังวลสำหรับksh, mksh, bash, zshหรือบอร์นเปลือกแม้ว่า - execทุกคนทำพื้นเดียวกันเป็นฉันได้อย่างชัดเจนข้างต้นด้วย


9

โดยปกติแล้วในกรณีที่มีข้อผิดพลาดคำสั่งจะส่งข้อความออกไปstderrดังนั้นสำหรับภารกิจของคุณstdout

mycommand > /dev/null


ขอบคุณ แต่ที่ฉันพูดในคำถามคำสั่งของฉันเข้าสู่ระบบออกทั้งหมดstderr(ดังนั้นจึงไม่มีผล)
Matthieu Napoli

4

ที่จะทำให้คุณเป็นคนเรื้อรัง

my_chronic() {
  tmp=$(mktemp) || return # this will be the temp file w/ the output
  "$@"  > "$tmp" 2>&1 # this should run the command, respecting all arguments
  ret=$?
  [ "$ret" -eq 0 ] || cat "$tmp"  # if $? (the return of the last run command) is not zero, cat the temp file
  rm -f "$tmp"
  return "$ret" # return the exit status of the command
}

3

ฉันทำอะไรแบบนี้ใน makefiles ของฉัน:

if (mycommand) &> mycommand.log; then 
  echo success 
else 
  c=$?; 
  echo;echo -e "Bad result from previous command, see mycommand.log for more details";echo;
  command_to_run_on_fail
  (exit $c)
fi

ปรับให้เข้ากับสถานการณ์ของคุณคุณสามารถทำสิ่งนี้:

if ! (mycommand) &> mycommand.log; then 
  c=$?; 
  cat mycommand.log
  rm mycommand.log
  (exit $c)
fi

ดังนั้น "if" จะรันคำสั่งและไพพ์เอาต์พุตไปยัง mycommand.log หากคุณต้องการจับ stdout เทียบกับ stdout เทียบกับอะไรก็ตามคุณอาจต้องเปลี่ยนคำสั่งไปป์ '&>' เป็น '>' หากคำสั่งล้มเหลวจากนั้นดักจับรหัสข้อผิดพลาดให้พิมพ์เนื้อหาของ mycommand.log ลบ mycommand.log และกลับมาพร้อมรหัสข้อผิดพลาดเดิมในที่สุด

หากไม่มี (exit $ c) คุณจะกลับมาพร้อมกับรหัสทางออกที่ตรงกับคำสั่ง 'rm' ที่ส่งคืน

ในที่สุดถ้าคุณต้องการซับหนึ่งสิ่งนี้จะทำงาน

mycommand &> mycommand.log || cat mycommand.log; rm mycommand.log

2
คุณห่อคำสั่ง / ฯลฯ ของคุณจริงๆ ใน(...)แบบนั้น เพราะมันไม่ได้ทำอะไรที่มีประโยชน์สำหรับคุณเลย
Etan Reisner

@EtanReisner (exit $c)กำลังตั้งค่า$?ซึ่งเป็นสิ่งที่คุณไม่สามารถทำได้เป็นอย่างอื่น if ! (mycommand) &>xมีความหมายกับการเปลี่ยนเส้นทางหากคำสั่งใช้เช่นtimeหรือจะให้ข้อผิดพลาดของเชลล์
Michael Homer

@MichaelHomer - สำหรับสิ่งเหล่านั้นมี{ ; }curlies ... แม้ว่าexitจะมีเล่ห์เหลี่ยมเล็กน้อยยอมรับ
mikeserv

ในตัวอย่างไฟล์ makefile หากคุณพยายามออกด้วยการบันทึกไว้ก่อนหน้านี้$?คุณสามารถใช้exit $cแต่ใช่ในกรณีอื่น(exit $?)มีค่า (แม้ว่าฟังก์ชั่นเชลล์rret() { return $1; }จะดีกว่าโดยทั่วไปที่ฉันเถียง) เชลล์ย่อยสำหรับคำสั่งยังคงไม่เหมือนที่ระบุใน mikeserv
Etan Reisner

3

ฉันเพิ่งพบคำตอบที่ง่ายกว่านี้สำหรับคำถามอื่น :

output=`mycommand 2>&1` || echo $output

ทำงานเหมือนจับใจ!


หมายเหตุ: สำหรับกรณีการใช้งานของฉันนี่เป็นวิธีที่ง่ายกว่ามาก (หลีกเลี่ยงการติดตั้งสิ่งเพิ่มเติมบนเซิร์ฟเวอร์ CI ทั้งหมด) ดังนั้นฉันเลือกที่จะทำเครื่องหมายสิ่งนี้ว่าเป็นที่ยอมรับ YMMV
Matthieu Napoli

โปรดทราบว่าหากคุณใช้ set -o xtrace ในเชลล์สคริปต์ของคุณเอาต์พุตทั้งหมดจะมีอีกครั้งซึ่งเป็นส่วนหนึ่งของการบันทึกรายละเอียดของการมอบหมายเอาต์พุต = ... :-) ในกรณีนั้นอาจใช้ดีกว่าเรื้อรัง
Jan-Philip Gehrcke
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.