Запуск исполняемого файла в PATH с тем же именем, что и у существующей функции

16

Иногда я определяю функцию, которая скрывает исполняемый файл и настраивает его аргументы или вывод. Поэтому имя функции совпадает с именем исполняемого файла, и мне нужен способ запуска исполняемого файла из функции без рекурсивного вызова функции. Например, для автоматического запуска вывода fossil diffчерез colordiffи less -Rя использую:

function fossil () {
    local EX=$(which fossil)
    if [ -z "$EX" ] ; then
        echo "Unable to find 'fossil' executable." >&2
        return 1
    fi
    if [ -t 1 ] && [ "$1" == "diff" ] ; then
        "$EX" "$@" | colordiff | less -R
        return
    fi
    "$EX" "$@"
}

Если бы я был уверен в расположении исполняемого файла, я мог бы просто напечатать /usr/bin/fossil. Bash признает, что это /означает, что команда - это исполняемый файл, а не функция. Но так как я не знаю точного местоположения, я должен прибегнуть к звонку whichи проверке результата. Есть ли более простой способ?

Петр Пудлак
источник
1
Вы говорите: «Bash признает, что это /означает, что команда является исполняемым файлом, а не функцией». Строго говоря, это не так. В то, что я считаю ужасным (и недокументированным) дизайнерским решением, bash позволяет именам функций содержать косую черту. Косая черта просто приводит /usr/bin/fossilк тому, что она отличается от строкиfossil , поэтому, когда вы говорите /usr/bin/fossil, она не пытается запустить fossilфункцию.
G-Man говорит: «Восстановите Монику»

Ответы:

19

Используйте commandвстроенную оболочку:

bash-4.2$ function date() { echo 'at the end of days...'; }

bash-4.2$ date
at the end of days...

bash-4.2$ command date
Mon Jan 21 16:24:33 EET 2013

bash-4.2$ help command
command: command [-pVv] command [arg ...]
    Execute a simple command or display information about commands.

    Runs COMMAND with ARGS suppressing  shell function lookup, or display
    information about the specified COMMANDs.  Can be used to invoke commands
    on disk when a function with the same name exists.
manatwork
источник
2
Еще один вариант - избежать команды \date.
Иордания
4
@jordanm, это работает только для псевдонимов. Вопрос был о функциях. pastebin.com/TgkHQwbb
manatwork
3

В сценариях #!строка часто используется /bin/env bashдля запуска команды bash на основе пути. (Это может отличаться для некоторых утилит). Это должно работать и здесь ...

( commandАльтернатива также должна работать, но может зависеть от конкретной оболочки) (она работает на Bourne Shell в Solaris, но на самом деле она работает /bin/commandв этом случае, который является встроенной в Bash оболочкой)

И то, /bin/commandи другое /bin/envуказано в SUS, поэтому все совместимые реализации должны иметь его.

Герт ван ден Берг
источник
Спасибо за указание env. Я сомневался, какой ответ мне следует принять, но поскольку вопрос касается bash , его встроенное commandрешение является лучшим решением.
Петр Пудлак
1
На моем Linux нет commandисполняемого файла, но commandтакже работает в dash, kshи zsh. Поэтому я предполагаю, что это встроенная оболочка не только в bash. pastebin.com/fi3gyNse
manatwork
Это не сборка на Solaris 10 Bourne (он также доступен как семейная реликвия-sh). Преимущества исполняемого файла с известным путем в том, что он не может быть перезаписан функцией.
Герт ван ден Берг
(Отсутствие команды / bin / может объяснить, почему скрипты используют /bin/envпосле хэш-удара, если они не хотят жестко кодировать путь оболочки)
Герт ван ден Берг
3

Ответ Герта заставил меня понять, что можно использовать и niceдля этой цели (на самом деле это было в одном из моих сценариев, не осознавая этого):

$ function date() { echo 'at the end of days...'; }
$ date
at the end of days...
$ nice -n0 date
Mon Jan 21 16:45:21 CET 2013

Это менее элегантно, чем другие ответы, но в некоторых случаях это может быть полезным вариантом.

Петр Пудлак
источник
Вы можете расширить это включить подобную альтернативу: `which date`.
Элия ​​Каган
1
@EliahKagan Проблема в `which something`том, что если нет somethingисполняемого файла, могут произойти неприятные вещи. Например, если echoотсутствует, то `which echo` /bin/rm preciousFileделает что-то совсем другое, чем предполагалось.
Петр Пудлак