bash: уникнути окремих ліній від відлуння `-x`


11

У bash, при запуску з -xопцією, чи можна звільнити окремі команди від лунання?

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

Я пам’ятаю ще в погані старі .batчаси, коли під час запуску echo onокремі рядки можна було звільнити, починаючи їх з а @. Чи є еквівалент у баші?

#!/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

Відповіді:


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 localoptionsв 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 d чи ні.


Солодке! Я дивився, чи є якісь модифікатори, які я можу застосувати до самої функції, але не думав про те, щоб просто перенаправити stderr. Дякую!
clacke

1
Btw , stchaz.free.fr/which_interpreter з тієї ж сторінки досить приголомшливий і тривожний. :-)
clacke

І ось я знову повернувся сюди за другим методом, замовчуючи набір + x, не замовчуючи корисний висновок stderr. Знову дякую!
клаке

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
  "$@"
}

Оригінальна команда виконується в одній оболонці під перетворенням ідентичності. Незадовго до запуску ви отримуєте нерекурсивний xtrace аргументів. Це дозволяє xtrace команди, які вам важливі, без спаму 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); "$@";}
Stéphane Chazelas

Ні, вибачте, unix.stackexchange.com/a/60049/17980 - це рішення, яке я шукав. :-) Чи set -xкупують мені маневри що-небудь порівняно з просто printf >&2 '+ %s\n' "$*"?
клаке

Як і в:xtrace() { printf >&2 '+ %s\n' "$*"; "$@"; }
клаке
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.