Как выполнять команды библиотеки из оболочки?

Итак, я понял, что работаю в обратном направлении, и это сработало для меня

sudo find . -type f \( -name '*.squashfs' -o -name "*.SQFS" \) -exec cp {}  /tmp/fs.squashfs  \; && sudo unsquashfs /tmp/fs.squashfs

Что я в итоге получил благодаря помощи пользователей! (Мне нужна была возможность поиска по разным параметрам и возможность добавить больше в будущем)

find /tmp/mnt \( -iname '*.squashfs' -o -iname "*.SQFS" \) -exec unsquashfs -d /tmp/squashfs-root/ {} \;
27
16.12.2018, 06:24
3 ответа

Команда aproposполезна во многих отношениях, но она также дает вам много «мусора». Большинство вещей, которые вы перечисляете, являются подпрограммами библиотеки C (, для этого предназначен раздел 3 руководства ), которые вы не можете использовать непосредственно из оболочки.

Чтобы их использовать, вам нужно написать программу на C, которая их вызывает. Это выходит за рамки тем, охватываемых этим конкретным сайтом (, это будет тема на StackOverflow).

Вот, таким образом, ответы на ваши вопросы:

  1. Вы не можете, это подпрограммы библиотеки C.
  2. Вы не можете, если вы не пишете программу на C.

Я знаю, что вы это знаете, но для полноты картины :В оболочке, если у вас есть строка в переменной string, вы можете сделать

string='hello world'
printf 'Length of string "%s" is %d\n' "$string" "${#string}"

Это напечатает Length of string "hello world" is 11в терминале, где 11исходит из ${#string}, которое расширяется до длины строки в $string.

Внутри оболочка вполне может использовать один из библиотечных вызовов, которые вы перечислили, для вычисления длины.

Это наиболее эффективный способ получить длину строки, хранящейся в переменной оболочки, в самой оболочке.

Также обратите внимание, что ${#string}— это расширение параметра оболочки POSIX , поэтому оно переносимо между всеми оболочками, которые заявляют о любой степени соответствия POSIX.

28
27.01.2020, 19:39

Возможно, вам не следует этого делать, но вы можете. Ответ Кусалананды лучше подходит для поставленной задачи и объясняет проблему.Поскольку вы спросили конкретно, как использовать любые библиотечные вызовы внутри терминала, вот несколько способов...


Tiny C Compiler(tcc)поддерживает -runфлаг , который позволяет вам (фактически )интерпретировать код C путем написания небольшой программы, поэтому вы можете использовать любые библиотечные вызовы внутри терминала посредством одного вызова этого.

Вы можете запустить функцию strnlenследующим образом:

$ tcc -run <(echo '#include <stdio.h>'; echo '#include <string.h>'; echo 'void main(int argc, char **argv) {printf("%i\n", strnlen(argv[1], 1024));}') "Hello world"
11

При этом используется подстановка процесса из Bash, zsh и других оболочек для предоставления tccфайла для чтения, который, по-видимому, содержит результаты всех echos; есть другие варианты.

Вы можете создать функцию, которая будет генерировать это для вас:

call_library_function_s_i() {
    func=$1
    shift
    tcc -run <(echo '#include <stdio.h>'; echo '#include <string.h>'; echo 'void main(int argc, char **argv) {printf("%i\n", '$func'(argv[1]));}') "$*"
}
$ call_library_function_s_i strlen hello world

(Я использовал strlenздесь, так что это строка унарной функции ->int -вам понадобится отдельная функция для каждой другой арности и типа возвращаемого значения ).


Другим вариантом является подключаемый модуль ctypes.shBash Тэвиса Орманди, который объединяет dlopenи dlsym. Это, вероятно, самое близкое приближение к тому, что вы пытались. Вы можете использовать, например,:

$ dlcall -r uint64 strlen "hello world"

и вызовет функцию, как и ожидалось.

Это самый прямой способ сделать это "из терминала", но вряд ли это будет что-то из вашего дистрибутива, поэтому вам придется устанавливать его вручную (, что нетривиально ). Вот несколько информативных цитат с собственного веб-сайта ctypes.sh, чтобы дать общее представление о том, как люди относятся к этому:

  • "that's disgusting"
  • "this has got to stop"
  • "you've gone too far with this"

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


... так что я сделал один!dlcall позволяет вызывать библиотечные функции из командной строки:

$ dlcall strnlen "hello world" 6
$ dlcall sin 2.5
$ dlcall strchr "hello world" -c ' '

Он поддерживает ограниченный набор прототипов функций, в настоящее время он не очень надежен или отказоустойчив, но теперь он существует.


Вы также можете использовать, например, Python и python -c 'import ctypes; import sys; print(ctypes.cdll.LoadLibrary("libc.so.6").strlen(" ".join(sys.argv[1:])))' hello world, но это, безусловно, не самый простой способ. Perl, Ruby и другие языки имеют схожие функции, которые вы могли бы использовать.


Итак, ответы на ваши вопросы:

  1. Используйте один из описанных выше подходов.
  2. Вам нужно использовать другую команду для начальной загрузки в библиотеку или часть программного обеспечения, которое подключается к вашей оболочке.

В общем, вам почти наверняка будет лучше сделать это любым другим способом.

40
27.01.2020, 19:39

Я бы не стал делать это только для strlen(), но иногда это полезный прием для проверки кода C.

user@host:~$ gdb gdb
(gdb) start
Temporary breakpoint 1,... in main ()
(gdb) print strlen("foobar")
$1 = 6

Здесь gdb— отладчик GNU, и обычно для отладки после него требуется имя программы. Поскольку у нас его нет, этот пример дает его для отладки. Затем startзапускает программу, после чего gdbможно использовать для выполнения произвольного кода на C.

16
27.01.2020, 19:39

Теги

Похожие вопросы