考虑lshw
作为示例程序,以下是ldd
给出的内容:
$ ldd /usr/sbin/lshw
linux-vdso.so.1 => (0x00007fff8bdaf000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x000000360e400000)
libsqlite3.so.0 => /lib64/libsqlite3.so.0 (0x0000003631600000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x000000360ec00000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000000360d800000)
libc.so.6 => /lib64/libc.so.6 (0x000000360c000000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x000000360cc00000)
libdl.so.2 => /lib64/libdl.so.2 (0x000000360c800000)
libm.so.6 => /lib64/libm.so.6 (0x000000360c400000)
/lib64/ld-linux-x86-64.so.2 (0x000000360bc00000)
如果我想找到共享库的绝对位置(并且出于明显的原因想要排除 linux-vdso.so.1),我该怎么做?将 awk 与正则表达式一起使用似乎很脆弱。ldd
有一个详细标志(-v),它确实打印共享库的完整路径,但它对于机器读取不太友好。
还有其他方法可以解决这个问题吗?如果有人知道这样做的系统调用,我也同意。
PS:对于一些上下文,我想在chroot
监狱中运行这个程序,所以我需要确保共享库全部可用。静态编译它可以避免所有这些戏剧性的事情,但这是我希望避免的道路。
更新:
我想我可能在阅读 Michael Kerrisk 的书《Linux 编程接口》时发现了可能更合适的东西。如果我运行一个程序$ LD_DEBUG=libs lshw
,它会输出各种有用的信息。例如:
$ LD_DEBUG=libs lshw
32058: find library=libresolv.so.2 [0]; searching
32058: search cache=/etc/ld.so.cache
32058: trying file=/lib64/libresolv.so.2
32058:
32058: find library=libstdc++.so.6 [0]; searching
32058: search cache=/etc/ld.so.cache
32058: trying file=/lib64/libstdc++.so.6
32058:
32058: find library=libgcc_s.so.1 [0]; searching
32058: search cache=/etc/ld.so.cache
32058: trying file=/lib64/libgcc_s.so.1
32058:
32058: find library=libc.so.6 [0]; searching
32058: search cache=/etc/ld.so.cache
32058: trying file=/lib64/libc.so.6
32058:
32058: find library=libm.so.6 [0]; searching
32058: search cache=/etc/ld.so.cache
32058: trying file=/lib64/libm.so.6
32058:
32058:
32058: prelink checking: ok
32058:
32058: calling init: /lib64/ld-linux-x86-64.so.2
32058:
32058:
32058: calling init: /lib64/libc.so.6
32058:
32058:
32058: calling init: /lib64/libm.so.6
32058:
32058:
32058: calling init: /lib64/libgcc_s.so.1
32058:
32058:
32058: calling init: /lib64/libstdc++.so.6
32058:
32058:
32058: calling init: /lib64/libresolv.so.2
<more output>
我想,如果我查找“calling init”行,我将拥有它在开始执行程序之前初始化的共享库路径。
答案1
您可以尝试 awk 而不使用正则表达式:
ldd /bin/ls | awk 'NF == 4 {print $3}; NF == 2 {print $1}'
输出:
/lib/x86_64-linux-gnu/libselinux.so.1
/lib/x86_64-linux-gnu/librt.so.1
/lib/x86_64-linux-gnu/libacl.so.1
/lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libdl.so.2
/lib64/ld-linux-x86-64.so.2
/lib/x86_64-linux-gnu/libpthread.so.0
/lib/x86_64-linux-gnu/libattr.so.1
答案2
我知道您说过您不需要正则表达式,但是该行中的“=>”使其易于解析。即使是详细模式也使用它,因此您甚至可以通过正则表达式(经过一些调整)将详细输出传递给正则表达式。我只是使用这样的命令作为循环变量列表(for i in ...)来设置 chroot 环境。
因此,我将为您提供两种方法,首先使用 sed:
ldd /path/to/binary | egrep -v 'linux-vdso|ld-linux-x86-64' | sed 's/.*\=> \(.*\) (.*/\1/'
或者,您可以尝试通过空格和 cut 来解析它,例如:
ldd /path/to/binary | egrep -v 'linux-vdso|ld-linux-x86-64' | cut -f 3 -d ' '
这两个都给了我以下内容:
ldd /bin/ls | egrep -v 'linux-vdso|ld-linux-x86-64' | cut -f 3 -d ' '
/lib/libselinux.so.1
/lib/librt.so.1
/lib/libacl.so.1
/lib/libc.so.6
/lib/libdl.so.2
/lib/libpthread.so.0
/lib/libattr.so.1
答案3
使用 GNU grep:
ldd /usr/sbin/lshw | grep -Po '/.*(?= \(0x)'
如果您可以保证这些路径不包含空格字符,则可以将其简化为:
ldd /usr/sbin/lshw | grep -o '/[^ ]*'
和sed
:
ldd /usr/sbin/lshw | sed -n 's,[^/]*\(/.*\) (0x.*,\1,p'
这个想法是获得从第一个/
到最后一个的所有内容(0x