Команда вызова функции Bash, заданная в качестве аргумента - PullRequest
5 голосов
/ 05 июля 2010

Как написать в bash функцию, которая выполняет команду, заданную в качестве аргумента, где

  • Данная команда может быть псевдонимом
  • Аргументы должны передаваться точно так, как дано; оценка невозможна

Другими словами, как написать максимально прозрачную оболочку функцию.

Цель функции-обертки может, например, заключаться в том, чтобы установить текущий каталог до и после данной команды и / или установить переменные среды или время, которое занимает данная команда, ... В качестве простого примера здесь я возьмите функцию, которая просто печатает строку и затем выполняет данную команду.

Первая попытка:

function wrap1 {
   echo Starting: "$@"
   "$@"
}

Вы можете использовать его как wrap1 echo hello. Но проблема в том, что вы не можете выполнить alias myalias echo и затем позвонить wrap1 myalias hello: это не разрешит псевдоним.

Еще одна попытка с использованием eval:

function wrap2 {
   echo Starting: "$@"
   eval "$@"
}

Теперь вызов псевдонима работает. Но проблема в том, что он тоже оценивает аргументы. Например, wrap2 echo "\\a" печатает только a вместо \a, потому что аргументы вычисляются дважды.

shopt -s expand_aliases, похоже, здесь тоже не помогает.

Есть ли способ оценить псевдонимы, такие как wrap2, но передать аргументы напрямую, как wrap1?

Ответы [ 2 ]

7 голосов
/ 05 июля 2010

Вы (э-э, я) можете использовать printf% q для экранирования аргументов.На первый взгляд экранирование с помощью printf и последующее выполнение eval всегда дают тот же результат, что и передача аргументов напрямую.

wrap() {
    echo Starting: "$@"
    eval $(printf "%q " "$@")
}
0 голосов
/ 05 июля 2010

Кажется возможным с двойным eval:

eval "eval x=($(alias y | cut -s -d '=' -f 2))"
# now the array x contains the split expansion of alias y
"${x[@]}" "${other_args[@]}"

Так что, возможно, ваша функция могла бы быть написана следующим образом:

wrap() {
    eval "eval prefix=($(alias $1 | cut -s -d '=' -f 2))"
    shift
    "${prefix[@]}" "$@"
}

Однако eval - это зло, а double eval - это двойное зло, и псевдонимы не раскрываются в сценариях по причине.

...