Скрыть вывод команды оболочки только в случае успеха?

12

Скрытие вывода команды оболочки обычно включает в себя перенаправление stderr и stdout. Существуют ли какие-либо встроенные средства или команды, которые по умолчанию скрывают вывод, но при ошибке сбрасывают весь накопленный вывод? Я хотел бы запустить это в качестве оболочки для удаленных sshкоманд. Теперь я использую перенаправление, но не понимаю, что заставило их потерпеть неудачу, и они слишком многословны.

РЕДАКТИРОВАТЬ: В конце я создал следующий шаблон на основе ответа @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 все равно будет отображаться; это достаточно для вас, или вы хотите видеть стандартный вывод, если есть ошибка?
Кромей
Я хочу видеть оба, но только если что-то пойдет не так, иначе я не хочу ничего видеть.
Гжегож Адам Ханкевич
2
Что я делаю, так это печатаю stdout & stderr в лог-файл, чтобы он не загромождал экран. Я также печать STDERR на экран, так что если это и ошибка , я могу видеть это. Если мне нужны подробности, я могу проверить файл журнала, который содержит вывод программы и ошибки программы в контексте. Таким образом, я могу «видеть оба, но только если что-то пойдет не так». Это помогает? См stackoverflow.com/questions/2871233/...
Стефан Lasiewski
1
Безопасно ли перенаправлять stderr и stdout в один файл с двумя отдельными перенаправлениями? Я думал, что мы всегда должны использовать 2>&1что-то вроде:$* >>"${SILENT_LOG}" 2>&1" || report_and_exit
Псмит

Ответы:

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
Бельмин Фернандес
источник
Злоумышленник, имеющий доступ без полномочий root в вашей системе, может попытаться создать символическую ссылку между rm и вызовом команды, которая будет указывать на /etc/passswdдругой критический файл или перезаписывать содержимое.
Митар
1
Кстати, порядок перенаправлений выше должен быть таким: $* > /tmp/surpress.out 2>&1Это действительно захватывает stderr.
Митар
2
$*не лучший способ справиться с произвольным вводом. Особенно, когда он содержит пробелы или флаги. Большинство портативных в ${1+"$@"}соответствии с stackoverflow.com/questions/743454/...
balrok
Изменено в обоих комментариях. Спасибо --- хорошая информация.
Бельмин Фернандес
Правописание merriam-webster.com/dictionary/suppress
Хатшепсут
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 $?
Zoredache
источник
5

Я не думаю, что есть чистый способ сделать это, единственное, о чем я могу думать, это

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

Реализация этого может быть интересным проектом, но, возможно, за пределами вопросов и ответов.

user9517
источник
Должно быть выполнимо с функцией. Хм, позвольте мне попробовать.
Бельмин Фернандес
1

шорт с чем-то вроде tehcommand &>/tmp/$$ || cat /tmp/$$

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

Короткий скрипт @zoredache - это, по сути, прото-оболочка для этого, которая обеспечит большую надежность, обрабатывает параллелизм и т. д.

rogerovo
источник
1

Попробуй так:

out=`command args...` || echo $out
user2743554
источник
2
Я написал бы это какout="$(command args...)" || echo "$out"
kasperd