使用内置的Bash运行exec


9

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

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

我希望此功能甚至可以与Shell内置程序一起使用,例如clock time ls -R应该输出time内置程序的结果,而不是/usr/bin/time可执行文件的结果。但是exec总是最终改为运行命令。

如何使Bash函数作为包装程序工作,该包装程序还接受shell内置参数作为参数?

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


您需要使用显式调用Shell exec bash -c \' "$@" \'。除非第一个参数中的命令被识别为Shell脚本,否则它将被解释为直接运行的二进制文件。另外,更简单地说,就是从原始shell中错过execand调用"@"
AFH 2015年

Answers:


9

您定义了一个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

在这种情况下,如果我知道正在运行实际的命令,则运行$@和之间有什么区别exec $@吗?
酒精2015年

3
使用时exec,该命令将替换外壳。因此,由于可执行文件是通过系统调用执行的,因此不再有内置函数,别名,特殊保留字,定义的字execve()。该系统调用需要一个可执行文件。
混乱

但是从外部观察者的角度来看,仍然可以区分它们,例如,exec $0只有一个过程,而$@仍然有两个过程。
酒精2015年

4
是的,$@正在运行的shell作为父进程,命令作为子进程。但是,当您要使用内置插件,别名等时,必须保留外壳。或开始一个新的。
混乱

4

启动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 pleasesudo command

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

1

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

#!/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但是,它无法处理,因此可能会有更好(更简洁)的解决方案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.