bash: экранирование отдельных строк из `-x`

11

В bash, при запуске с -xопцией, возможно ли исключить отображение отдельных команд?

Я пытаюсь сделать вывод настолько аккуратным, насколько это возможно, поэтому я запускаю определенные части моего скрипта в подоболочке set +x. Тем не менее, сама строка set +xвсе еще отображается и не добавляет никакой ценной информации к выводу.

Я помню, что в старые добрые .batвремена, когда работали с echo on, отдельные строки можно было освободить, начав их с @. Есть ли какой-нибудь эквивалент в bash?

#!/bin/bash -x

function i_know_what_this_does() {
  (
    set +x
    echo do stuff
  )
}

echo the next-next line still echoes 'set +x', is that avoidable?
i_know_what_this_does
echo and we are back and echoing is back on

При выполнении вышеизложенного вывод:

+ echo the next-next line still echoes 'set +x,' is that 'avoidable?'
the next-next line still echoes set +x, is that avoidable?
+ i_know_what_this_does
+ set +x
do stuff
+ echo and we are back and echoing is back on
and we are back and echoing is back on
clacke
источник

Ответы:

22

xtraceвывод идет в stderr, так что вы можете перенаправить stderrна /dev/null:

i_know_what_this_does() {
  echo do stuff
} 2> /dev/null

Если вы все еще хотите видеть ошибки команд, запускаемых внутри функций, вы можете сделать

i_know_what_this_does() (
  { set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
)

Обратите внимание на использование (...)вместо {...}предоставления локальной области действия для этой функции через подоболочку. bashТак как версия 4.4 теперь поддерживает, local -как в оболочке Almquist, чтобы сделать опции локальными для функции (аналогично set -o localoptionsin zsh), вы можете избежать подоболочки, выполнив:

i_know_what_this_does() {
  { local -; set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

Альтернативой для bash4.0 к 4.3 было бы использовать $BASH_XTRACEFDпеременную и открыть /dev/nullдля этого выделенный дескриптор файла :

exec 9> /dev/null
set -x
i_know_what_this_does() {
  { local BASH_XTRACEFD=9; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

Так как bashне хватает возможности пометить fd с помощью флага close-on-exec , это побочный эффект - утечка этого fd другим командам.

Смотрите также этот locvar.sh , который содержит несколько функций для реализации локальных возможностей для переменных и функций в сценариях POSIX , а также обеспечивает trace_fnи untrace_fnфункцию , чтобы сделать их xtrace я или нет.

Стефан Шазелас
источник
Сладкий! Я искал, есть ли какие-либо модификаторы, которые я мог бы применить к самой функции, но я не думал о простом перенаправлении stderr. Спасибо!
Clacke
1
Кстати, stchaz.free.fr/which_interpreter с той же страницы довольно удивительный и тревожный. :-)
клик
И теперь я вернулся сюда снова для второго метода: заставить замолчать set + x без заглушения полезного вывода stderr. Еще раз спасибо!
Clacke
2

Причина, по set +xкоторой выводится это то, что set -xозначает «напечатать команду, которую вы собираетесь запустить, с расширениями, перед ее запуском . Таким образом, оболочка не знает, что вы хотите, чтобы она не печатала данные до тех пор, пока не напечатает строку, сообщающую об этом не печатать вещи. Насколько я знаю, нет никакого способа остановить это.

Дженни Д
источник
0

Вот решение, которое вы искали:

function xtrace() {
  # Print the line as if xtrace was turned on, using perl to filter out
  # the extra colon character and the following "set +x" line.
  (
    set -x
    # Colon is a no-op in bash, so nothing will execute.
    : "$@"
    set +x
  ) 2>&1 | perl -ne 's/^[+] :/+/ and print' 1>&2
  # Execute the original line unmolested
  "$@"
}

Исходная команда выполняется в той же оболочке при преобразовании идентичности. Непосредственно перед запуском вы получаете нерекурсивное выражение аргументов. Это позволяет вам извлекать команды, о которых вы заботитесь, без spamming stederr с дубликатами каждой команды "echo".

# Example
echo "About to do something complicated ..."
xtrace do_something_complicated
Дейв Допсон
источник
Или чтобы избежать perl(и проблем с многострочными командами):+() { :;} 2> /dev/null; xtrace() { (PS4=; set -x; + "$@";{ set +x; } 2> /dev/null); "$@";}
Стефан Шазелас
Нет, извините, unix.stackexchange.com/a/60049/17980 - это решение, которое я искал. :-) set -xМаневры покупают мне что-нибудь по сравнению с просто printf >&2 '+ %s\n' "$*"?
глухой
Как в:xtrace() { printf >&2 '+ %s\n' "$*"; "$@"; }
Clacke