我认为任何命令的参数位置都是不固定的。
例如,cp -r ./abc ./def
和cp ./abc ./def -r
是相同的,grep -rnH hello .
和grep hello . -rnH
是相同的......
然而,今天当我使用的时候ldd
,我发现我错了。因为ldd -r x.so
和ldd x.so -r
不一样。第二个命令给了我一个错误:
ldd: ./-r: No such file or directory
为什么我们不能改变参数的位置ldd
?
答案1
一些 GNU 实用程序会默默地重新组织命令行参数,以便选项和选项参数位于操作数之前。这不是标准行为。
符合标准的实用程序期望选项和选项参数首先出现,当命令行解析器找到第一个非选项参数时,其余参数将被视为操作数:
cp -i file1 file2
在上面,第一个参数是选项,最后两个参数是操作数。
cp file1 file2 -i
上面有三个操作数,非 GNU 实现cp
会将file1
和复制file2
到名为的目录中-i
(如果不存在这样的目录,则给出错误消息)。cp
另一方面,GNU将其-i
视为一个选项,并询问我是否要覆盖file2
该文件(如果该文件存在)。
通过设置环境变量可以纠正此行为POSIXLY_CORRECT
:
$ cp file1 file2 -i
cp: overwrite 'file2'? n
$ POSIXLY_CORRECT=1 cp file1 file2 -i
cp: target '-i' is not a directory
或者你可以--
用明确地标记选项的结尾(无论命令是否以 GNU 方式解析其选项,这都会起作用):
$ cp -- file1 file2 -i
cp: target '-i' is not a directory
在以下事情中需要记住这一点:
grep 'PATTERN' *.txt
对于 GNUgrep
你需要这样写:
grep -- 'PATTERN' *.txt
或者
grep -e 'PATTERN' -- *.txt
如果PATTERN
某些.txt
文件的名称或名称以-
.
您的ldd
(在 GNU 系统上是一个bash
手动解析选项的脚本,而不是使用 GNU getopt_long()
API)不会以“GNU 方式”解析其命令行参数,(恕我直言)它做得正确。
来自 GNU 文档getopt_long(3)
:
默认情况下,在扫描时
getopt()
排列 的内容argv
,以便最终所有非选项都位于末尾。 [...] 如果设置了optstring
is的第一个字符+
或环境变量POSIXLY_CORRECT
,则一旦遇到非选项参数,选项处理就会停止。