如何从 shell 执行库命令?

如何从 shell 执行库命令?

我想简单地计算字符串的长度(即哈希值)。所以,我打开终端并执行以下操作:

$ apropos length

这给我返回了一堆命令/函数,它们的末尾有(3)或附加了它们。(3ssl)现在男人男人为我们提供有关这些section numbers含义的信息。

3   Library calls (functions within program libraries)

出于好奇,我只是尝试了所有这些命令(希望至少有一个可以工作)

strcspn (3)          - get length of a prefix substring
strlen (3)           - calculate the length of a string
strnlen (3)          - determine the length of a fixed-size string
strspn (3)           - get length of a prefix substring
wcslen (3)           - determine the length of a wide-character string
wcsnlen (3)          - determine the length of a fixed-size wide-character string

每个命令都得到同样的错误

$ strnlen HelloWorld 
$ strnlen: command not found

嗯,我知道shell中如何求字符串的长度使用wc -mexpr length其他解决方法。

但是,我这里有两个问题:

  1. 如何使用任何library calls (3)壳里面?
  2. 如何仅使用库调用而不使用其他命令来计算字符串长度?

注意:问题主要集中在一般情况library calls及其在 shell 中的用法。这使得第一个问题的回答变得更加重要。

答案1

你可能不应该这样做,但你可以。拘萨罗南达的回答更适合手头的任务并解释问题。既然你具体问了如何使用任何不过,在终端内部调用库,有几种方法......


Tiny C 编译器 ( 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 和其他 shell 提供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是一个一元函数 string->int - 对于每个不同的数量和返回类型,您需要一个单独的函数)。


另一种选择是Bashctypes.sh插件塔维斯·奥曼迪 (Tavis Ormandy) 撰写,结束了dlopendlsym.这可能是最接近您所尝试的。例如,您可以使用:

$ dlcall -r uint64 strlen "hello world"

它会按预期调用该函数。

这是“从终端”执行此操作的最直接方法,但它不太可能是您的发行版打包的东西,因此您必须手动安装它(这很重要)。这里有一些信息引用ctypes.sh自自己网站给出人们对此有何感受的总体印象:

  • “真恶心”
  • “这必须停止”
  • “你已经做得太过分了”

其他 shell 可能也有类似的工具,但我不知道。从理论上讲,没有理由没有一个独立的命令可以完全针对简单的情况执行此操作,但令我有些惊讶的是我还没有找到一个......


...所以我做了一个! 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. 需要使用另一个命令来引导您进入库,或者一个挂接到您的 shell 中的软件。

总而言之,几乎可以肯定,以其他方式执行此操作会更好。

答案2

apropos命令在很多方面都很有用,但它也确实给您带来了很多“垃圾”。您列出的大部分内容都是 C 库例程(这就是手册第 3 节的内容),您不能直接从 shell 使用它们。

要使用它们,您必须编写调用它们的 C 程序。这超出了该特定站点涵盖的主题范围(该主题将位于堆栈溢出)。

因此,这些是您问题的答案:

  1. 你不能,它们是 C 库例程。
  2. 你不能,除非你写一个C程序。

我知道你知道这一点,但为了完整起见:在 shell 中,如果变量中有一个字符串string,你可以这样做

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

Length of string "hello world" is 11这将在终端中打印,其中11的来源${#string}扩展为 中字符串的长度$string

在内部,shell 很可能正在使用您列出的库调用之一来进行长度计算。

这是在 shell 中获取存储在 shell 变量中的字符串长度的最有效方法。

还要注意的${#string}POSIX shell 参数扩展,因此它可以在所有声称具有任何程度的 POSIX 合规性的 shell 之间移植。

答案3

我不会仅仅为了 这样做strlen(),但有时对于尝试 C 代码来说这是一个有用的技巧。

用户@主机:~$ gdb gdb
(gdb)启动
临时断点1,...在main()中
(gdb) 打印 strlen("foobar")
1 美元 = 6

gdb是 GNU 调试器,通常会在其后面加上一个程序名称来进行调试。因为我们没有,所以这个例子让它自己进行调试。然后start启动程序,之后gdb可以用来执行任意C代码。

答案4

一个可用于交互式调用共享库中函数的工具:“Witchcraft Compiler Collection”。https://github.com/endrazine/wcc

从 GitHub 页面:

wsh :巫术外壳

巫术 shell 接受 ELF 共享库、ELF ET_DYN 可执行文件和用 Punk-C 编写的巫术 Shell 脚本作为输入。它将所有可执行文件加载到自己的地址空间中,并使其 API 可用于在其嵌入式解释器中进行编程。这提供了类似于通过 Java 等语言的反射提供的二进制功能。

wsh 的用法示例 以下命令/usr/sbin/apache2在 wsh 中加载可执行文件,调用ap_get_server_banner()apache 中的函数来检索其横幅并将其显示在wsh解释器中。

jonathan@blackbox:~$ wsh /usr/sbin/apache2
> a = ap_get_server_banner()
> print(a)
Apache/2.4.7

相关内容