Когда вы по уши в аллигаторах, легко забыть, что целью было осушить болото.
- народная поговорка
Вопрос об 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
shebang.
Неявно пользователь может удалить 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
или просто#!/ Бен / ш
и это должно работать как ожидалось.
- иметь такой код
(shebang) команда 1 команда 2 команда 3 команда set -x 4 команда 5 команда 6 set +x команда 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
, и bash не пытается рекурсивно развернуть текст замены.
Неудивительно, что последний ответ (ответ с 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
сообщение об ошибке неверного адреса и
- основной дамп.