Когда вы по уши в аллигаторах, легко забыть, что целью было осушить болото.
- народная поговорка
Вопрос в том 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. Но, если она есть #!/bin/bash
, вам нужно добавить shopt -s expand_aliases
команду, чтобы псевдонимы работали в сценарии.)
Итак, для моего первого трюка:
alias echo='{ set +x; } 2> /dev/null; builtin echo'
Теперь, когда мы говорим echo "Message"
, мы называем псевдоним, который не отслеживается. Псевдоним отключает параметр трассировки, подавляя при этом сообщение трассировки из set
команды (используя технику, представленную сначала в ответе пользователя 5071535 ), а затем выполняет фактическую 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
- и мы можем, с немного более хитрым. Но прежде чем представить это, подумайте об этом. ОП начинается со сценариев, которые используют #!/bin/sh -ex
шебанг. Неявно пользователь может удалить x
из shebang и иметь скрипт, который работает нормально, без отслеживания выполнения. Было бы хорошо, если бы мы могли разработать решение, которое сохраняет это свойство. Первые несколько ответов здесь не соответствуют этому свойству, потому что они включают отслеживание «назад» после 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
) в начале сценария, а остальные оставить в покое.
Это позволит вам
- использовать любую из следующих строк Шебанга:
#! / bin / sh -ex
#! / bin / sh -e
#! / bin / sh –x
или просто#! / Bin / ш
и это должно работать как ожидалось.
- иметь такой код
(Шебанг)
команда 1
команда 2
команда 3
установить -x
команда 4
команда 5
команда 6
установить + х
команда 7
команда 8
команда 9
а также
- Команды 4, 5 и 6 будут отслеживаться - если только одна из них не является
echo
, и в этом случае она будет выполнена, но не будет отслежена. (Но даже если команда 5 является echo
командой, команда 6 все равно будет отслеживаться.)
- Команды 7, 8 и 9 не будут отслеживаться. Даже если команда 8 является
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
в псевдониме, я хотел бы увидеть это.