我想简单地计算字符串的长度(即哈希值)。所以,我打开终端并执行以下操作:
$ 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 -m
和expr length
其他解决方法。
但是,我这里有两个问题:
- 如何使用任何
library calls (3)
壳里面? - 如何仅使用库调用而不使用其他命令来计算字符串长度?
注意:问题主要集中在一般情况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
一个要读取的文件,该文件似乎包含所有echo
s 的结果;还有其他选择。
你可以创建一个函数来为你生成这个:
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) 撰写,结束了dlopen
和dlsym
.这可能是最接近您所尝试的。例如,您可以使用:
$ 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 和其他语言具有您可以使用的类似功能。
所以你的问题的答案是:
- 使用上述方法之一。
- 你做需要使用另一个命令来引导您进入库,或者一个挂接到您的 shell 中的软件。
总而言之,几乎可以肯定,以其他方式执行此操作会更好。
答案2
该apropos
命令在很多方面都很有用,但它也确实给您带来了很多“垃圾”。您列出的大部分内容都是 C 库例程(这就是手册第 3 节的内容),您不能直接从 shell 使用它们。
要使用它们,您必须编写调用它们的 C 程序。这超出了该特定站点涵盖的主题范围(该主题将位于堆栈溢出)。
因此,这些是您问题的答案:
- 你不能,它们是 C 库例程。
- 你不能,除非你写一个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