Коли ти до шиї у алігаторів, то легко забути, що метою було осушення болота.
- народна приказка
Питання полягає в тому echo
, і більшість відповідей поки що були зосереджені на тому, як проникнути set +x
команду. Є набагато простіше і пряме рішення:
{ echo "Message"; } 2> /dev/null
(Я визнаю, що я не міг би подумати про те, { …; } 2> /dev/null
якби не бачив цього в попередніх відповідях.)
Це дещо громіздко, але, якщо у вас є блок послідовних echo
команд, вам не потрібно робити це на кожній окремо:
{
echo "The quick brown fox"
echo "jumps over the lazy dog."
} 2> /dev/null
Зауважте, що вам не потрібні крапки з комою, коли у вас є нові рядки.
Ви можете зменшити тягар набору тексту, скориставшись ідеєю kenorb
про /dev/null
постійне відкриття нестандартного дескриптора файлів (наприклад, 3), а потім 2>&3
замість того, щоб постійно говорити 2> /dev/null
.
Перші чотири відповіді під час написання цього запиту вимагають робити щось особливе (а в більшості випадків громіздке)
кожного разу, коли ви робите це echo
. Якщо ви дійсно хочете, щоб усі echo
команди придушували слід виконання (а чому б і ні?), Ви можете зробити це в усьому світі, не змінюючи багато коду. По-перше, я помітив, що псевдоніми не простежуються:
$ myfunc()
> {
> date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016 0:00:00 AM # Happy Halloween!
$ myfunc
+ myfunc # Note that function call is traced.
+ date
Mon, Oct 31, 2016 0:00:01 AM
$ myalias
+ date # Note that it doesn’t say + myalias
Mon, Oct 31, 2016 0:00:02 AM
(Зверніть увагу, що такі фрагменти сценарію працюють, якщо shebang є #!/bin/sh
, навіть якщо /bin/sh
це посилання на bash. Але, якщо shebang є #!/bin/bash
, вам потрібно додати shopt -s expand_aliases
команду, щоб отримати псевдоніми для роботи в сценарії.)
Отже, для мого першого фокусу:
alias echo='{ set +x; } 2> /dev/null; builtin echo'
Тепер, коли ми говоримо echo "Message"
, ми називаємо псевдонім, який не простежується. Псевдонім вимикає параметр сліду, пригнічуючи повідомлення про сліду з set
команди (використовуючи методику, представлену спочатку у відповіді user5071535 ), а потім виконує фактичну echo
команду. Це дозволяє нам отримати ефект, подібний до відповіді користувача5071535, не потребуючи редагування коду в кожній echo
команді. Однак цей режим відстеження залишається вимкненим. Ми не можемо ввести set -x
псевдонім (або, принаймні, не просто), оскільки псевдонім дозволяє лише замінити рядок на слово; жодна частина рядка псевдоніму не може бути введена в команду
після аргументів (наприклад, "Message"
). Так, наприклад, якщо сценарій містить
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date
вихід буде
+ date
Mon, Oct 31, 2016 0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016 0:00:04 AM # Note that it doesn’t say + date
тому вам потрібно знову ввімкнути параметр сліду після відображення повідомлення (ив), але лише один раз після кожного блоку послідовних echo
команд:
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date
Було б непогано, якби ми могли зробити set -x
автоматику після echo
- і можемо, з трохи більше хитрістю. Але перед тим, як це зробити, врахуйте це. OP починається зі сценаріїв, які використовують #!/bin/sh -ex
шебанг. Користувач неявно міг би видалити x
з шебангу та створити сценарій, який працює нормально, без відстеження виконання. Було б добре, якби ми могли розробити рішення, яке зберігає цю властивість. Перші кілька відповідей тут не сприймають цю властивість, тому що вони без зволікання відслідковують "назад" після echo
висловлювань, не зважаючи на те, чи це вже було.
Ця відповідь помітно не вдається розпізнати це питання, оскільки воно замінює echo
вихід із слідовим виведенням; тому всі повідомлення зникають, якщо відстеження відключено. Зараз я представляю рішення, яке відновлює відстеження після echo
заяви, умовно - лише якщо воно вже було включене. Пониження цього рівня до рішення, яке беззастережно перетворює «назад», є тривіальним і залишається як вправа.
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
builtin echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
$-
- список опцій; з'єднання літер, відповідне всім параметрам, які встановлені. Наприклад, якщо встановлено параметри e
і та x
параметри, тоді $-
буде комбінація літер, що включає e
і x
. Мій новий псевдонім (вище) зберігає значення, $-
перш ніж відключити відстеження. Потім, вимикаючи трасування, він передає контроль над функцією оболонки. Ця функція спрацьовує фактично, echo
а потім перевіряє, чи x
була опція ввімкнена, коли викликався псевдонім. Якщо параметр був увімкнутий, функція його знову вмикає; якщо він був вимкнений, функція залишає його вимкненим.
Ви можете вставити вищевказані сім рядків (вісім, якщо ви включите shopt
) на початку сценарію, а решту залишити в спокої.
Це дозволило б вам
- використовувати будь-яку з наступних рядків shebang:
#! / bin / sh -ex
#! / бін / ш -е
#! / бін / ш –х
або просто простий#! / бін / ш
і це має працювати, як очікувалося.
- мати код, як
(shebang)
команда 1
команда 2
команда 3
встановити -x
команда 4
команда 5
команда 6
встановити + x
команда 7
команда 8
команда 9
і
- Команди 4, 5 і 6 будуть простежуватися - якщо тільки одна з них не є
echo
, в цьому випадку вона буде виконуватися, але не простежується. (Але навіть якщо команда 5 є an echo
, команда 6 все одно буде простежена.)
- Команди 7, 8 і 9 не простежуються. Навіть якщо команда 8 є an
echo
, команда 9 все одно не простежується.
- Команди 1, 2 і 3 будуть простежуватись (як 4, 5 і 6) чи ні (як 7, 8 і 9) залежно від того, чи включає в себе шебанг
x
.
PS Я виявив, що в моїй системі я можу залишити builtin
ключове слово у своїй середній відповіді (тій, для якої це лише псевдонім echo
). Це не дивно; bash (1) говорить, що під час розширення псевдоніму ...
… Слово, ідентичне псевдоніму, який розгортається, не розгортається вдруге. Це означає , що один може псевдонім , ls
щоб ls -F
, наприклад, і Баш не намагатися рекурсивно розширити текст заміни.
Не надто дивно, що остання відповідь (одна з echo_and_restore
) не вдається, якщо builtin
ключове слово опущено 1 . Але, як не дивно, це працює, якщо я видаляю builtin
і перемикаю замовлення:
echo_and_restore() {
echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
__________
1 Здається, це породжує невизначену поведінку. Я бачив
- нескінченна петля (можливо, через необмежену рекурсію),
/dev/null: Bad address
повідомлення про помилку та
- ядро звалища.
echo +x; echo "$*"; echo -x
у псевдонімі, я хотів би це побачити.