Приховати вихід команди оболонки лише на успіх?


12

Приховування виводу команди оболонки зазвичай включає перенаправлення stderr та stdout. Чи є якась вбудована програма чи команда, яка за замовчуванням приховує вихід, але після помилки скидає весь накопичений вихід? Я хотів би запустити це як обгортку для віддалених sshкоманд. Тепер я маю їх використовувати переадресацію, але я не розумію, що змусило їх вийти з ладу, і вони просто занадто багатослівні.

EDIT: Врешті-решт я створив наступний шаблон на основі відповіді @Belmin, який я трохи змінив, щоб накопичити всі попередні команди зі скрипту, використовувати поточний ідентифікатор процесу, автоматично видалити журнал та додати помилку червоної помилки повідомлення, коли щось піде не так. У цьому шаблоні початкові silentобгортки матимуть успіх, а потім відмовляються від третьої команди, оскільки каталог вже існує:

#!/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, якщо є помилка?
Кромей

Я хочу бачити і те, і інше, лише якщо щось піде не так, інакше я нічого не хочу бачити.
Grzegorz Adam Hankiewicz

2
Що я роблю, це надрукувати stdout & stderr у файл логінгу, щоб він не захаращував екран. Я також друкую stderr на екран, так що якщо є помилка, я можу це побачити. Якщо мені потрібні деталі, я можу перевірити файл журналу, який містить вихід програми та помилки програми в контексті. Таким чином я можу "бачити і те, і інше, але тільки якщо щось піде не так". Чи допомагає це? Див stackoverflow.com/questions/2871233 / ...
Стефан Lasiewski

1
Чи безпечно перенаправляти stderr та stdout до одного файлу двома окремими переадресаціями? Я думав, що ми завжди повинні використовувати 2>&1щось на кшталт:$* >>"${SILENT_LOG}" 2>&1" || report_and_exit
psmith

Відповіді:


3

Я б встановив функцію bash, як це:

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

Зловмисник, який має некореневий доступ у вашій системі, може спробувати здійснити символьне посилання між rm та викликом команди, яке вказувало б на /etc/passswdякийсь інший критичний файл та перезаписував би вміст.
Мітар

1
BTW, порядок переадресацій вище повинен бути: $* > /tmp/surpress.out 2>&1Це дійсно захоплює stderr.
Мітар

2
$*не найкраще обробляти довільне введення. Особливо, коли він містить пробіли чи прапори. Більшість портативних в ${1+"$@"}відповідно до stackoverflow.com/questions/743454 / ...
balrok

Змінено на обидва коментарі. Спасибі --- хороша інформація.
Белмін Фернандес


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

Я не думаю, що існує чистий спосіб зробити це, єдине, що я можу придумати

  • Захоплення результату команди.
  • Перевірте значення повернення команди та якщо вона не вдалася
    • відобразити захоплений вихід.

Реалізація цього може бути цікавим проектом, але, можливо, виходить за межі питань Q&A.


Потрібно виконати функцію. Гм, дозвольте спробувати.
Белмін Фернандес

1

невдача з чимось подібним tehcommand &>/tmp/$$ || cat /tmp/$$

залежить, скільки зручності / набору тексту вам потрібно / потрібно. (наприклад, використовуючи його як трубу або передаючи команду за аргументом)

Короткий сценарій @zoredache - це в основному прото-обгортка для цього, що дасть більше надійності, одночасності обробки тощо


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.