bash: переопределить echo для печати собственного префикса в скрипте - PullRequest
3 голосов
/ 04 декабря 2011

У меня есть несколько длинных скриптов, вызывающих друг друга, и я хочу, чтобы их вывод был более описательным. Идея состоит в том, чтобы настроить команду echo для каждого скрипта примерно так:

Мой вопрос: как сделать его нерекурсивным, используя echo?

это script1.sh

#!/bin/bash
#Original version:
#function echo(){ echo $(basename $0 .sh): $1; }
#Version after fixes
function echo(){ builtin echo -n "$(basename $0 .sh): ">&2; builtin echo $@ ; } 
echo Info
./script2.sh

это script2.sh

#!/bin/bash
#Original version:
#function echo(){ echo $(basename $0 .sh): $1; }
#Version after fixes
function echo(){ builtin echo -n "$(basename $0 .sh): ">&2; builtin echo $@ ; } 
echo Info
exit 0

поэтому вывод должен быть:

>./script1.sh
script1: Info
script2: Info

--- РЕДАКТИРОВАТЬ

Бонус:

>./script1.sh 2> /dev/null 
Info
Info

Ответы [ 3 ]

12 голосов
/ 04 декабря 2011

используйте ключевое слово builtin:

function echo(){ builtin echo $(basename $0 .sh): $1; }

здесь страница справки:

$ help builtin
builtin: builtin [shell-builtin [arg ...]]
    Execute shell builtins.

    Execute SHELL-BUILTIN with arguments ARGs without performing command
    lookup.  This is useful when you wish to reimplement a shell builtin
    as a shell function, but need to execute the builtin within the function.

    Exit Status:
    Returns the exit status of SHELL-BUILTIN, or false if SHELL-BUILTIN is
    not a shell builtin..
1 голос
/ 04 марта 2015

builtin работает только для внутренних команд оболочки, таких как echo. Я знаю, что исходный вопрос был конкретно связан с echo, но, поскольку это был популярный хит Google для «функции переопределения bash», я решил добавить свое решение для других команд. Я пишу обертку для изменения имени терминала, когда я запускаю ssh, поэтому я определил функцию с именем ssh и должен вызывать реальный двоичный файл изнутри. Возможно, это не лучший способ, но он работает так:

function ssh {
    $(which ssh) $@
}
0 голосов
/ 04 ноября 2012

Я предложил перенаправление ввода / вывода в качестве решения.Статья Bash Redirections с использованием Exec вдохновила меня.Он имеет следующие последствия:

  • Перенаправление стандартного скрипта или вывод ошибок независимо от того, какая команда печатает на нем, например, echo, printf и т. Д.
  • Нет повторяющихся операций для подоболочек или источниковscripts.
  • Перенаправление распространяется на любой исполняемый файл, вызываемый этим сценарием, его сценарий или индекс.
  • Фильтры могут быть составлены путем создания нескольких каналов, где один канал перенаправляет свой вывод вввод следующего и т. д.

В моих сценариях оболочки bash я использую:

alias start_log_ctx="start_filter_by_pipe_regex 2 s/.*/${0##*/}\(pid=$$\): \0/"
function start_filter_by_pipe_regex {
  declare -r a="$(mktemp -u)" #1
  mknod "$a" p                #2
  sed <"$a" ">&$1" "$2" &     #3
  exec "$1">"$a"              #4
}

alias stop_log_ctx_by_job="stop_filter_by_pipe_job 2"
def stop_filter_by_pipe_job {
  exec "$1">&- #1
  wait "$2" #2
}

По сути, псевдоним start_log_ctx использует sed для строки-wise (.*) фильтрует ввод / вывод скрипта, который идет к выводу ошибки (2) и добавляет базовое имя скрипта (${0##*/}) и идентификатор процесса (pid=$$) к каждой строке.Функция start_filter_by_pipe_regex работает следующим образом:

  1. Сохраняет абсолютный путь, но не создает (-U) временный файл.
  2. Создает канал под абсолютным путем[1.].
  3. Запуск sed в качестве фильтра на заднем плане (&).Пусть он читает (<) из канала [2.] и перенаправляет свой стандартный вывод (>) на дескриптор файла, заданный в качестве параметра 1..Передайте фильтр, заданный как параметр 2., в sed.
  4. Перенаправьте (>) дескриптор файла, заданный в качестве параметра 1., в канал [2.].

Псевдоним stop_log_ctx закрывает дескриптор файла вывода ошибок (2) и ожидает остановки ранее запущенного sed.Это неявно делает это после закрытия файлового дескриптора.Функция stop_filter_by_pipe_job выполняет следующие действия:

  1. Закройте дескриптор файла, заданный в качестве параметра 1., тем самым останавливая sed.
  2. Дождитесь фон sed, идентифицируемыйзадание bash, заданное как параметр 2. stop.

В начале своей основной функции я обычно выполняю declare -r a="$(start_log_ctx)" и заканчиваю stop_log_ctx_by_job "$a".

...