ซ่อนเอาต์พุตของคำสั่งเชลล์เฉพาะเมื่อสำเร็จหรือไม่


12

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

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

#!/bin/sh

set -e

SILENT_LOG=/tmp/silent_log_$$.txt
trap "/bin/rm -f $SILENT_LOG" EXIT

function report_and_exit {
    cat "${SILENT_LOG}";
    echo "\033[91mError running command.\033[39m"
    exit 1;
}

function silent {
    $* 2>>"${SILENT_LOG}" >> "${SILENT_LOG}" || report_and_exit;
}

silent mkdir -v pepe
silent mkdir -v pepe2
silent mkdir -v pepe
silent mkdir -v pepe2

2
หากคุณเปลี่ยนเส้นทางเฉพาะ stdout เท่านั้น stderr จะยังคงปรากฏขึ้น มีเพียงพอสำหรับคุณหรือคุณต้องการเห็น stdout ด้วยหากมีข้อผิดพลาด
Kromey

ฉันต้องการเห็นทั้งคู่ แต่ถ้ามีอะไรผิดปกติไม่งั้นฉันก็ไม่อยากเห็นอะไรเลย
Grzegorz Adam Hankiewicz

2
สิ่งที่ฉันทำคือพิมพ์ stdout & stderr ไปที่ logfile ดังนั้นมันจึงไม่เกะกะหน้าจอ ฉันยังพิมพ์ stderr ไปยังหน้าจอดังนั้นหากมีเป็นข้อผิดพลาดและฉันสามารถดูได้ ถ้าฉันต้องการรายละเอียดฉันสามารถตรวจสอบ logfile ซึ่งมีเอาต์พุตของโปรแกรมและข้อผิดพลาดของโปรแกรมในบริบท ด้วยวิธีนี้ฉันสามารถ 'ดูทั้งสองอย่างถ้ามีอะไรผิดพลาด' สิ่งนี้ช่วยได้ไหม? ดูstackoverflow.com/questions/2871233/…
Stefan Lasiewski

1
การเปลี่ยนเส้นทาง stderr และ stdout ไปยังไฟล์เดียวกันนั้นปลอดภัยหรือไม่ที่มีการเปลี่ยนเส้นทางสองแบบแยกกัน ฉันคิดว่าเราควรใช้เสมอ2>&1สิ่งที่ต้องการ:$* >>"${SILENT_LOG}" 2>&1" || report_and_exit
psmith

คำตอบ:


3

ฉันต้องการตั้งค่าฟังก์ชันทุบตีดังนี้:

function suppress { /bin/rm --force /tmp/suppress.out 2> /dev/null; ${1+"$@"} > /tmp/suppress.out 2>&1 || cat /tmp/suppress.out; /bin/rm /tmp/suppress.out; }

จากนั้นคุณสามารถเรียกใช้คำสั่ง:

suppress foo -a bar

ผู้โจมตีที่มีการเข้าถึงที่ไม่ใช่รูทบนระบบของคุณสามารถลองสร้าง symlink ระหว่าง rm และ command call ซึ่งจะชี้ไปที่/etc/passswdหรือไฟล์สำคัญอื่น ๆ และรับเนื้อหาที่เขียนทับ
Mitar

1
BTW ลำดับของการเปลี่ยนเส้นทางด้านบนควรเป็น: $* > /tmp/surpress.out 2>&1สิ่งนี้จับ stderr ได้จริงๆ
Mitar

2
$*ไม่ใช่วิธีที่ดีที่สุดในการจัดการอินพุตโดยพลการ โดยเฉพาะอย่างยิ่งเมื่อมันมีช่องว่างหรือธง พกพาส่วนใหญ่เป็น${1+"$@"}ไปตามstackoverflow.com/questions/743454/…
balrok

แก้ไขต่อความคิดเห็นทั้งสอง ขอบคุณ --- ข้อมูลที่ดี
Belmin Fernandez


7

มันควรจะง่ายพอที่จะเขียนสคริปต์เพื่อจุดประสงค์นี้

บางอย่างเช่นสคริปต์ที่ยังไม่ผ่านการทดสอบอย่างสมบูรณ์

OUTPUT=`tempfile`
program_we_want_to_capture &2>1 > $OUTPUT
[ $? -ne 0 ]; then
    cat $OUTPUT
    exit 1
fi
rm $OUTPUT

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

#!/bin/bash

the_command 2>&1 | awk '
BEGIN \
{
  # Initialize our error-detection flag.
  ErrorDetected = 0
}
# Following are regex that will simply skip all lines
# which are good and we never want to see
/ Added UserList source/ || \
/ Added User/ || \
/ init domainlist / || \
/ init iplist / || \
/ init urllist / || \
/ loading dbfile / || \
/^$/ {next} # Uninteresting message.  Skip it.

# Following are lines that we good and we always want to see
/ INFO: ready for requests / \
{
  print "  " $0 # Expected message we want to see.
  next
}

# any remaining lines are unexpected, and probably error messages.  These will be printed out and highlighted.
{
  print "->" $0 # Unexpected message.  Print it
  ErrorDetected=1
}

END \
{
  if (ErrorDetected == 1) {
    print "Unexpected messages (\"->\") detected in execution."
    exit 2
  }
}
'
exit $?

5

ฉันไม่คิดว่าจะมีวิธีที่สะอาดในการทำสิ่งนี้สิ่งเดียวที่ฉันคิดได้ก็คือ

  • จับเอาท์พุทของคำสั่ง
  • ตรวจสอบค่าส่งคืนของคำสั่งและหากล้มเหลว
    • แสดงเอาท์พุทที่จับ

การดำเนินการนี้อาจเป็นโครงการที่น่าสนใจ แต่อาจเกินกว่าคำถาม & คำตอบ


ควรจะทำได้ด้วยฟังก์ชั่น หืมมมให้ฉันลองดู
Belmin Fernandez

1

จะสั้นด้วยบางสิ่งเช่น tehcommand &>/tmp/$$ || cat /tmp/$$

ขึ้นอยู่กับความสะดวกในการใช้งาน / การพิมพ์ที่คุณต้องการ / ต้องการ (เช่นใช้เป็นไพพ์หรือส่งคำสั่งด้วยอาร์กิวเมนต์)

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


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