Набір Bash + x без його друку


92

Хтось знає, чи ми можемо сказати 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

Відповіді:


145

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

set -x
command
{ set +x; } 2>/dev/null

10
Чудова відповідь, лише примітка: без крапки з комою після команди це не спрацює; а з крапкою з комою, але без пробілів у фігурних дужках, буде піднята синтаксична помилка.
sdaau

9
Це обнуляє статус виходу.
Garth Kidd

8
Статус виходу @GarthKidd обнуляється при кожній успішній команді. set +xє настільки вдалою командою
Даніель Олдер

3
У тих випадках , коли вам потрібен статус виходу 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 )

Ну, спасибі ... хороший момент. Насправді мені відомий "фокус під оболонкою". Я сподівався, що це може бути простіше. Він передбачає суттєві зміни в коді, що робить код складнішим і менш читабельним. ІМХО, це було б гірше, ніж жити з набором + х ліній ...
Андреас Шпіндлер

Я не розумію, як ( set -x \n command \n )гірше ніж set -x \n command \n set +x.
Чепнер

3
@chepner: Ви не можете встановити змінні.
choroba

2
... а ви не можете cd: це не змінює поточний каталог у батьківській оболонці.
Андреас Шпіндлер,

Вибачте, я не впевнений, що я вважав вашим фактичним запереченням. Це був довгий тиждень ...
Чепнер

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

Розумний фокус (хоча вам не потрібна /dev/stdinчастина). Застереження полягає в тому, що включення розширення псевдонімів у сценаріях може мати небажані побічні ефекти.
mklement0 07

Ти маєш рацію. Я відредагував відповідь, щоб видалити зайве /dev/stdin. Я не знаю жодних конкретних побічних ефектів, оскільки неінтерактивне середовище не повинно завантажувати файли, що визначають псевдоніми. Які побічні ефекти можуть бути?
user108471 07

1
Це хороший момент - я забув, що псевдоніми не успадковуються, тому ризик набагато менший, ніж я думав (гіпотетично, ваш скрипт може отримувати сторонній код, який випадково визначає псевдоніми, але я згоден, що це, мабуть, не є реальним світовий концерн). +1
mklement0 07

1
@AndreasSpindler Не могли б Ви детальніше пояснити, чому, на Вашу думку, ця техніка з більшою ймовірністю витікає більш конфіденційну інформацію?
user108471

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

Коли виконується:

$ ./test.sh 
+ echo hello
hello
status: 0
+ exit 56
status: 56

Хороші зусилля, але я думаю, що ()навколо exitне потрібно. Гаразд. Можливо, це параноїчно, але якщо цей код використовується загалом, у вас є хороший вектор атаки: перевизначити trace_onта trace_offі ввести код, який читає виконані команди. Якщо ви використовуєте такі "утиліти" поодинці, це повчально, але якщо код використовується разом з іншими, вам слід подумати, чи переваги таких нестандартизованих функцій переважають недоліки. Особисто я вирішив, { set +x; } 2>/dev/nullоскільки ця конструкція загально зрозуміла і теж не змінює статус виходу.
Андреас Шпіндлер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.