I have created a command line utility using C programming language. Now I want to embed that command into bash. It should act as bash built-in command 'cd'. How can I do that??
In the bash source I saw there is a directory called builtins
. I looked that directory and found there is *.def
files and there is a file called cd.def
.
I think this is the definition of bash built-in cd
. Now my question is how to create my own definition???
If you wish to make your binary a built-in in bash
Method 1 : bash function
You can emulate the behavior by creating a bash function in, say ~/.bashrc
, file:
function mycommand
{
/path/to/your/binary #plus arguments if any
}
export -f mycommand
and the use mycommand
just like you use cd
.
Do have a look at this [ tldp article ] on how this differ from an actual built-in.
Method 2 : using enable
I thought I would demonstrate this by creating a new builtin for finding factorial. Below is the code I've written :
/* 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*
};
Compile the code like below :
gcc -shared -fpic -o factorial.so factorial.c
Copy the shared object factorial.so to to a local lib location say /usr/local/lib/mylib/
Enable(persistent) the new builtin by adding the below in ~/.bashrc (or /etc/bash.bashrc if you wish the new builtin to be used by other users)
enable -f /usr/local/lib/mylib/factorial.so factorial60 # You need to give the full path
And voila! you have the new builtin ready for use in a new shell session.
$ 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'
(thanks @chepner for reminding this)
Method 3 : recompile bash
Just recompile bash(the dirty way!) with added functionality - [ source code here ].
References:
enable
manpage [ here ].bash-builtins
library (I'm on Ubuntu 12.04,The actual package name may differ by distro) to compile new builtins.builtin_usage
is [ defined ].enable
the name of the builtin (here factorial60) should match the name given in the structure (notice factorial60_struct
) and _struct
should be appended to the builtin name in the structure.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With