Bash set + x без его печати

95

Кто-нибудь знает, можем ли мы сказать set +xв bash без его печати:

set -x
command
set +x

следы

+ command
+ set +x

но он должен просто напечатать

+ command

Bash - это версия 4.1.10 (4). Это меня уже некоторое время беспокоит - вывод загроможден бесполезными set +xстроками, что делает средство трассировки не таким полезным, как могло бы быть.

Андреас Шпиндлер
источник
Это не отвечает на ваш вопрос, но почему бы и нет, когда вы запустите свой скрипт:script.sh 2>&1 | grep -v 'set +x'
cdarke

Ответы:

148

У меня была такая же проблема, и я смог найти решение, в котором не используется подоболочка:

set -x
command
{ set +x; } 2>/dev/null
МакДжоуи
источник
10
Отличный ответ, примечание: без точки с запятой после команды это не сработает; а с точкой с запятой, но без пробелов в фигурных скобках, возникнет синтаксическая ошибка.
sdaau
9
Это обнуляет статус выхода.
Гарт Кидд
8
@GarthKidd Статус выхода обнуляется при каждой успешной команде. set +xтакая успешная команда
Дэниел Алдер
4
В тех случаях , когда вам нужен статус выхода command, это изменение является решением: { STATUS=$?; set +x; } 2>/dev/null. Затем $STATUSна досуге просмотрите следующие строки.
Грег Прайс
5
Отдельно, вот версия golfed немного дальше: { set +x; } 2>&-. Это полностью закрывает fd 2, а не указывает на / dev / null. Некоторые программы не справляются с такой задачей при попытке печати в stderr, поэтому / dev / null в целом - хороший стиль; но set -xтрассировка оболочки прекрасно справляется с этим, так что здесь она отлично работает и делает это заклинание немного короче.
Грег Прайс
43

Вы можете использовать подоболочку. После выхода из подоболочки настройка xбудет потеряна:

( set -x ; command )
чороба
источник
Что ж, спасибо ... хорошее замечание. На самом деле я знаю "трюк с суб-оболочкой". Я надеялся, что это может быть проще. Это включает в себя существенные изменения кода, которые делают его более сложным и менее читаемым. ИМХО, это было бы хуже, чем жить с установленными + x линиями ...
Андреас Шпиндлер
Не понимаю, что ( set -x \n command \n )может быть хуже set -x \n command \n set +x.
chepner 02
3
@chepner: нельзя устанавливать переменные.
choroba
2
... и вы не можете cd: он не меняет текущий каталог в родительской оболочке.
Андреас Шпиндлер
Извините, я не совсем понимаю, в чем состоят ваши возражения. Это была долгая неделя ...
chepner 02
8

Совсем недавно я взломал решение этой проблемы, когда меня это рассердило:

shopt -s expand_aliases
_xtrace() {
    case $1 in
        on) set -x ;;
        off) set +x ;;
    esac
}
alias xtrace='{ _xtrace $(cat); } 2>/dev/null <<<'

Это позволяет включать и отключать xtrace, как показано ниже, где я регистрирую, как аргументы назначаются переменным:

xtrace on
ARG1=$1
ARG2=$2
xtrace off

И вы получите результат, который выглядит так:

$ ./script.sh one two
+ ARG1=one
+ ARG2=two
user108471
источник
Умный трюк (правда, вам не нужна /dev/stdinроль). Предостережение заключается в том, что включение раскрытия псевдонимов в скриптах может иметь нежелательные побочные эффекты.
mklement0 07
Ты прав. Отредактировал ответ, чтобы убрать лишнее /dev/stdin. Мне не известны какие-либо конкретные побочные эффекты, поскольку неинтерактивная среда не должна загружать файлы, определяющие псевдонимы. Какие могут быть побочные эффекты?
user108471 07
1
Это хороший момент - я забыл, что псевдонимы не наследуются, поэтому риск намного меньше, чем я думал (гипотетически, ваш скрипт может использовать сторонний код, который определяет псевдонимы, но я согласен, что, вероятно, это не настоящий - мировой концерн). +1
mklement0 07
1
@AndreasSpindler Не могли бы вы пояснить, почему вы думаете, что этот метод с большей вероятностью приведет к утечке более конфиденциальной информации?
user108471 09
1
... в основном потому, что псевдонимы и функции являются конструкциями высокого уровня. set +xгораздо труднее (если не невозможно) пойти на компромисс. Но это по-прежнему хорошее и прямое решение - возможно, лучшее на данный момент.
Андреас Шпиндлер
7

Как насчет решения на основе упрощенной версии @ user108471:

shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ set +x; } 2>/dev/null'

trace_on
...stuff...
trace_off
Оливер
источник
Как насчет этого? function () { set_plus_x='{ set +x; } 2>/dev/null' }
LexH
1

Это комбинация нескольких идей, которые могут заключить блок кода и сохранить статус выхода.

#!/bin/bash
shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ PREV_STATUS=$? ; set +x; } 2>/dev/null; (exit $PREV_STATUS)'

trace_on
echo hello
trace_off
echo "status: $?"

trace_on
(exit 56)
trace_off
echo "status: $?"

При исполнении:

$ ./test.sh 
+ echo hello
hello
status: 0
+ exit 56
status: 56
user3286792
источник
Хорошая попытка , но я думаю , что ()вокруг exitнет необходимости. ОК. Может быть, параноик, но если этот код используется в основном у вас есть вектор хорошей атаки: Переопределить trace_onи trace_offи ввести код , который считывает команду выполняется. Если вы используете только такие «утилиты», это поучительно, но если код используется с другими, вы должны подумать, перевешивают ли преимущества таких нестандартных функций недостатки. Лично я смирился, так { set +x; } 2>/dev/nullкак эта конструкция обычно понимается и тоже не меняет статус выхода.
Андреас Шпиндлер
Спасибо. Я поделился этим подходом со своими коллегами, и им нравится, что он снижает уровень шума и вывода, и кода. Что касается ()всего exit 56; это было просто для того, чтобы я мог продемонстрировать, что статус выхода подпроцесса доступен в сценарии bash; без скобок он не стал бы подпроцессом, и в этот момент скрипт завершился бы со статусом = 65.
user3286792