如何将一个命令嵌入到bash中以作为内置命令?

5
我使用C编程语言创建了一个命令行实用程序。现在我想将该命令嵌入到bash中。它应该像bash内置命令“cd”一样运行。 我该怎么做?
我在bash源代码中看到了一个名为builtins的目录。我查看了该目录,发现有*.def文件和一个名为cd.def的文件。
我认为这是bash内置命令“cd”的定义。现在我的问题是如何创建自己的定义?

5
你无法将它嵌入到bash中,但是你可以将它复制到路径中的某个位置,比如/usr/bin或者/usr/local/bin。然后只需要输入它的名字就可以运行了。 - par
5
您需要构建一个自定义版本的 bash。 - Samuel Peter
4
您可以通过使用“enable”命令加载新的内置功能。但这可能涉及修改实用程序,使其以正确的形式进行加载。源代码分发提供了许多示例。examples. - chepner
3个回答

3

如果您希望将二进制文件成为bash中的内置命令

方法1:创建bash函数

您可以通过在~/.bashrc文件中创建bash函数来模拟这种行为:

function mycommand 
{
/path/to/your/binary #plus arguments if any
}

export -f mycommand

使用mycommand的方式与使用cd的方式相同。

请查看此[ tldp文章 ],了解这种方法与实际内置命令的区别。

方法2:使用enable

我想通过创建一个用于查找阶乘的新内置命令来演示这一点。下面是我编写的代码:

/* Programme to compute the factorial of numbers up to 60 */

#include <bash/config.h>

#if defined(HAVE_UNISTD_H)
  #include <unistd.h>
#endif

#include <bash/shell.h>    // for shell internals
#include <bash/builtins.h> // for struct builtin

#include <stdio.h>
#include <stdlib.h> // for atoi

/* For unsigned long long numbers, my system could handle numbers
 * upto 65 when it comes to factorial, but I'm restricting the value
 * to 60 for the sake of the example so naming my builtin 'factorial60' 
 * the wrapper is factorial_wrapper and the actual task of computing the  
 * factorial is done by the function 'factorial'which resides inside the 
 * wrapper.
 */

unsigned long long factorial(unsigned long long x, unsigned long long amt)
{
  if (x == 0)
    return amt;
  else
    amt*=x;
  return factorial(x-1, amt);
}

int factorial_wrapper(WORD_LIST* list) //Wrapper function
{
  char* ptr=NULL;
  int num;
  if (list == 0) {
    builtin_usage();
    fflush(stdout);
    return (EX_USAGE);
  }
  else{
    ptr=list->word->word;

    /* We're expecting one & only one argument here.
     * I haven't checked for multiple arguments for the sake of brevity
     */
    num=atoi(ptr);

    /* atoi is not the best here because it returns zero for invalid conversions
     * I used it just for the sake of this example.
     */

    if (num>60){
    builtin_usage();
    fflush(stdout);
    return (EX_USAGE);
    }

    printf("%llu\n",factorial(num,1));
    fflush(stdout);
  }
  return (EXECUTION_SUCCESS);     // returning 0
}


char *factorial60_doc[] = {
  "factorial60",
  "Usage : factorial60 number",
  "Description :",
  "Gives the factorial of numbers upto 60",
  (char *)NULL
};
//  Make sure the above documentation is sensible
//   You need to supply factorial60_doc to the structure below.


struct builtin factorial60_struct = {
  "factorial60", // builtin name
  factorial_wrapper, // wrapper function for implementing the builtin
  BUILTIN_ENABLED, // initial flags for builtin  - See Reference 1
  factorial60_doc, // array of long documentation strings.
  "Usage : factorial60 'number_upto_60'", // usage synopsis; becomes short_doc
  NULL // reserved for internal use, this a char*
};

按照以下方式编译代码:

gcc -shared -fpic -o factorial.so factorial.c

将共享对象factorial.so复制到本地库位置,例如/usr/local/lib/mylib/

通过在~/.bashrc中添加以下内容(如果您希望其他用户使用新的内置命令,则可以添加到/etc/bash.bashrc中)来启用(持久化)新的内置命令:

enable -f /usr/local/lib/mylib/factorial.so factorial60  # You need to give the full path

完成!现在你已经有了新的内置命令,可以在新的shell会话中使用。

$ factorial60 24
10611558092380307456
$ factorial60
factorial60: usage: Usage : factorial60 'number_upto_60'
$ type -a factorial60
factorial60 is a shell builtin
$ factorial60 61
factorial60: usage: Usage : factorial60 'number_upto_60'

(感谢@chepner提醒)

方法三:重新编译Bash

通过重新编译Bash(有点“不太好”的方式!)添加功能 - [源代码在此]


参考资料:

  1. enable手册[这里]
  2. WORD_LIST:内置函数总是给予一个类型为WORD_LIST的列表指针。如果内置函数实际上不需要任何选项,则必须在任何进一步处理之前调用no_options(list)并检查其返回值。如果返回值为非零值,则您的函数应立即返回EX_USAGE值。检查[此处]
  3. 您需要安装bash-builtins库(我使用的是Ubuntu 12.04,实际软件包名称可能因发行版而异)以编译新的内置函数。
  4. 检查builtin_usage如何[定义]
  5. 要使用enable命令,您的系统应支持动态加载。
  6. enable中,内置函数的名称(这里是factorial60)应与结构中给定的名称相匹配(注意factorial60_struct),并且应将 builtin name 附加到结构中的_struct 后面。


cd不是一个二进制文件。如果它是的话,它就不会改变其子进程的工作目录。 - Ed Heal
你可以使用一个Bash函数。 - Ed Heal
@EdHeal:已更新 :-) - sjsam
“cd” 内置并非出于性能原因。 - Ed Heal

-1

你也可以使用alias,只需在~/.bashrc中添加以下行即可完成任务。

alias commandname='/path/to/your/binary'

-2
您可以将其安装到用户路径的直接部分。通常是以下之一: "/bin" 或 "/usr/bin" - 您需要具有机器上的root访问权限才能执行此操作。
或者 "~/bin" - 如果仅针对您的用户并且您没有root访问权限。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接