扩展 bash 内置命令

  • 内容
  • 评论
  • 相关

一些常用的操作如 sleep,cat 等一般是通过调用单独的外部命令来执行。 在对一些 shell 脚本做优化时,或者让系统进程树更清晰,或者尽可能的减少进程 fork 的次数时总是想尽可能的通过调用 bash 的内置命令来实现类似的功能,在使用内置 命令实现过于复杂时通过编写扩展编译出动态库来扩展 bash 内置命令也是一个办法。

对于 sleep,可以通过 bash 内置的 read 命令的超时功能来实现,如下的例子通过创建 命名管道后读写该管道来实现 sleep 的功能:

waitfifo=/tmp/fifo-demo-only
[ -p ${waitfifo} ] || mkfifo ${waitfifo}
while true ; do    
read -t 1 <>${waitfifo}
done

  其他的功能则需要尽可能的利用 bash 已有的内置命令结合一些技巧来实现。这里我们 介绍另一种方法,通过 bash 内置的 enable 命令的 “-f” 参数能动态加载代码来实现 任意内置命令。还是以 sleep 为例,假设其源代码(附在本文最后)为 sleep.c,参考如下过程演示:

$ enable -n sleep # 禁止 sleep 内置命令,如果有
$ type sleep
sleep 是 /usr/bin/sleep
$ gcc -DHAVE_CONFIG_H -fPIC -shared -Wl,-soname,sleep sleep.c -o sleep.so
$ enable -f ./sleep.so  sleep
$ type sleep
sleep 是 shell 内嵌
$ sleep -h
sleep: 用法:sleep seconds[.fraction]

  事实上,对于 Gentoo 系统,只需要对 bash 的 USE flags 加上 plugins 即可拥有 bash 源代码里已经实现了的动态加载内置命令,查看目录 /usr/lib/bash/

$ equery uses bash 
...  
* Found these USE flags for app-shells/bash-4.2_p45:
...  
+ + plugins      : Add support for loading builtins at runtime via 'enable' 
...

对 Ubuntu 则需要先通过

1
apt-get install bash-builtins

安装相应的头文件后再来 编译相关的代码。

sleep.c 的源代码如下:

/**

 * @file

 * @brief sleep — sleep for bash builtin

 */

#include <unistd.h>

// for Gentoo, replace bash-plugins w/ bash if Ubuntu

#include <bash-plugins/shell.h>

#include <bash-plugins/builtins.h>

int sleep_builtin (WORD_LIST *list)

{

    long    sec, usec;

    struct timespec tv;

    if (list == 0) {

        builtin_usage();

        return(EX_USAGE);

    }

    if (*list->word->word == '-' || list->next) {

        builtin_usage ();

        return (EX_USAGE);

    }

    if (uconvert(list->word->word, &sec, &usec)) {

        tv.tv_sec = sec;

        tv.tv_nsec = usec * 1000;

        nanosleep(&tv, NULL);

        return(EXECUTION_SUCCESS);

    }

    builtin_error("%s: bad sleep interval", list->word->word);

    return (EXECUTION_FAILURE);

}

static char *sleep_doc[] = {

    "Suspend execution for specified period.",

    "sleep suspends execution for a minimum of SECONDS[.FRACTION] seconds.",

    (char *)NULL

};

struct builtin sleep_struct = {

    "sleep",

    sleep_builtin,

    BUILTIN_ENABLED,

    sleep_doc,

    "sleep seconds[.fraction]",

    0

};