Как создавать команды оболочки из функций C

Хотите знать, как взять набор функций C и превратить их в команды shell/bash.

Скажем, у меня есть простой набор функций C

int
fn1() {
  // some C code for function 1.
}

int
fn2() {
  // some C code for function 2.
}

int
fn3() {
  // some C code for function 3.
}

Я хотел бы затем каким-то образом создавать команды CLI, чтобы я мог использовать их из терминала.

$ fn1 <param> <param> ...
$ fn2 ...
$ fn3 ...

Не уверен, что процесс делает это. Если мне нужно как-то переписать все интерфейсы функций в сценарии оболочки, а затем каким-то образом вызвать функцию C, вроде как (сценарий bash):

fn1() {
  callc mylib/fn1 $1 $2
}

fn2() {
  ...
}

...

Или если я могу просто каким-то образом преобразовать каждую функцию C в скрипт оболочки автоматически, разделив их на отдельные файлы fn1.c, fn2.cи т. д. и как-то загружать их в оболочку source ~/.bash_profile Тип вещи.

Любая помощь будет оценена, спасибо.

3 ответа

Или, возможно, перейдите к старой школе: напишите код на C, чтобы проверить, как он вызывался (0-й аргумент из исходных аргументов командной строки), и вызовите правильную функцию C на основе этого имени. Требуется скомпилировать такую ​​программу на C в один исполняемый файл, а затем создать символические ссылки на базовое приложение, где символические ссылки являются именами интересующих функций. Не требуется никакого шелл-кода, кроме установки здесь артефактов - исполняемого файла и символических ссылок - в каталог в вашем $PATH.

Пример. Если следующий код называется toybox.c, а ~/bin существует и находится в $ PATH пользователя, используйте что-то вроде:

$ cc -o ~/bin/toybox toybox.c
$ ln -s toybox ~/bin/fn1
$ ln -s toybox ~/bin/fn2
$ ln -s toybox ~/bin/fn3

Простые тесты - только показывает, что строительные леса на месте.

$ fn1
fn1 invoked - no arguments.
$ fn3 1 2 'a b c'
fn3 invoked - arguments:
  1 - '1'
  2 - '2'
  3 - 'a b c'

Исходный код для toybox.c может выглядеть так:

#include <string.h>
#include <libgen.h>
#include <stdio.h>

struct name2func {
    const char *name;
    int (*func)(int ac, char *const av[]);
};

void
fn_debug(const char *fn, int ac, char *const av[])
{
    int n;

    printf("%s invoked - ", fn);

    if (ac <= 0) {
        printf("no arguments.\n");
    } else {
        printf("arguments:\n");
        for (n = 0; n < ac; n++) {
            printf("  %d - '%s'\n", n + 1, av[n]);
        }
    }
}

int
fn1(int ac, char *const av[])
{
    fn_debug("fn1", ac, av);
    /* some C code for function 1. */
    return 0;
}

int
fn2(int ac, char *const av[])
{
    fn_debug("fn2", ac, av);
    /* some C code for function 2. */
    return 0;
}

int
fn3(int ac, char *const av[])
{
    fn_debug("fn3", ac, av);
    /* some C code for function 3. */
    return 0;
}

/*
 * Establish a crude symbol table after function definitions: size of
 * the name2func array (i.e., its number of elements) is available via the
 * sizeof builtin.
 */

struct name2func n2f[] = {
  { "fn1", fn1 },
  { "fn2", fn2 },
  { "fn3", fn3 }
};

int
dispatch(const char *func_name, int ac, char *const av[])
{
    size_t n;

    /* linear search ok for small # of funcs */

    for (n = 0; n < sizeof n2f / sizeof n2f[0]; n++) {
        if (strcmp(func_name, n2f[n].name) == 0) {
            return (*n2f[n].func)(ac, av);
        }
    }

    fprintf(stderr, "%s: unsupported\n", func_name);
    return 1;
}

int
main(int argc, char *const argv[])
{
    /*
     * using POSIX basename(3) to create, say, "fn1" from
     * a full-path invocation like "/my/odd/dir/fn1".
     */
    char *fnbase = basename(argv[0]);

    if (fnbase == 0) {
        perror("basename");
        return 1;
    }

    return dispatch(fnbase, argc - 1, argv + 1);
}

Напишите один исполняемый файл C со всеми функциями в нем... затем создайте для них псевдонимы или создайте сценарии оболочки-оболочки.

Обратите внимание, псевдонимы не будут принимать параметры, но вы можете использовать функции для этого: https://askubuntu.com/questions/626458/can-i-pass-arguments-to-an-alias-command

Псевдонимы:

alias function-x="set_of_c_functions.exe --run function_x"
alias function-y="set_of_c_functions.exe --run function_y"

сценарии: /usr/bin/function-x.sh

#!/bin/bash
/path/to/set_of_c_functions --run function_x -options ${@}
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    printf("I am a shell command with these arguments:\n");
    for (int i = 0; i < argc; ++i)
        printf("\t%s\n", argv[i]);
    return EXIT_SUCCESS;
}

Скомпилируйте выше, затем выполните команду "FullPathToDirectory/NameOfExecutableFile Argument1 Argument2".

Как только это сработает, либо переместите исполняемый файл в один из каталогов, перечисленных в переменной среды PATH, либо измените каталог PATH, включив в него каталог, содержащий исполняемый файл.

Некоторые снаряды требуют от вас выполнения rehash команда после помещения нового исполняемого файла в PATH.

Как только это сработает, измените программу по своему желанию.

Вы можете создавать отдельные программы для каждой команды. Если вы хотите, чтобы весь исходный код был в одной программе, распространенный метод - создать несколько ссылок файловой системы на исполняемый файл (как в Unix). ln команда) и использовать argv[0] содержимое, чтобы выбрать, какую функцию выполнять. (argv[0] обычно содержит путь к исполняемому файлу с именем файла в качестве последнего компонента.)

Другие вопросы по тегам