使用 Bash 内置命令运行‘exec’

使用 Bash 内置命令运行‘exec’

我定义了一个 shell 函数(我们称之为clock),我想将其用作另一个命令的包装器,类似于该time函数,例如clock ls -R

我的 shell 函数执行一些任务,然后以 结束exec "$@"

我希望这个函数即使在使用 shell 内置函数时也能工作,例如应该输出内置函数clock time ls -R的结果,而不是可执行文件。但最终总是运行命令。time/usr/bin/timeexec

如何使我的 Bash 函数作为包装器工作,并且还接受 shell 内置函数作为参数?

编辑:我刚刚了解到这time不是 Bash 内置的,而是一个特殊保留字与管道相关。即使它不适用于,我仍然对内置解决方案感兴趣,time但更通用的解决方案会更好。

答案1

您定义了一个 bash 函数。因此,调用该函数时,您已经处于 bash shell 中。因此,该函数可能看起来就像这样:

clock(){
  echo "do something"
  $@
}

该函数可以通过 bash 内置命令、特殊保留字、命令和其他定义的函数来调用:

别名:

$ clock type ls
do something
ls is aliased to `ls --color=auto'

bash 内置命令:

$ clock type type
do something
type is a shell builtin

另一个功能:

$ clock clock
do something
do something

可执行文件:

$ clock date
do something
Tue Apr 21 14:11:59 CEST 2015

答案2

启动 shell 内置命令或 shell 关键字的唯一方法是启动新 shell,因为 exec “用给定的命令替换 shell”。您应该将最后一行替换为:

IFS=' '; exec bash -c "$*"

这对于内置字和保留字都有效;原理是一样的。

答案3

如果包装器需要插入代码给定的命令,别名会起作用,因为它们在很早的阶段就被扩展了:

alias clock="do this; do that;"

别名几乎是逐字插入到别名词的位置,因此尾随;很重要 - 它使其clock time foo扩展为do this; do that; time foo

您可以滥用它来创建魔法别名甚至绕过引用。


用于插入代码一个命令,您可以使用“DEBUG”挂钩。

shopt -s extdebug
trap "<code>" DEBUG

具体来说:

shopt -s extdebug
trap 'if [[ $BASH_COMMAND == "clock "* ]]; then
          eval "${BASH_COMMAND#clock }"; echo "Whee!"; false
      fi' DEBUG

钩子仍在运行命令,但当它返回时,false它会告诉 bash 取消执行(因为钩子已经通过 eval 运行了它)。

作为另一个示例,您可以使用它来将别名command please设为sudo command

trap 'case $BASH_COMMAND in *\ please) eval sudo ${BASH_COMMAND% *}; false; esac' DEBUG

答案4

到目前为止我能想到的唯一解决方案是进行案例分析以区分第一个参数是命令,内置参数还是关键字,并在最后一种情况下失败:

#!/bin/bash

case $(type -t "$1") in
  file)
    # do stuff
    exec "$@"
    ;;
  builtin)
    # do stuff
    builtin "$@"
    ;;
  keyword)
    >&2 echo "error: cannot handle keywords: $1"
    exit 1
    ;;
  *)
    >&2 echo "error: unknown type: $1"
    exit 1
    ;;
esac

但是,它不能处理time,因此可能存在更好(且更简洁)的解决方案。

相关内容