Yve*_*ves 0 command-line command arguments
我认为任何命令的参数位置都是不固定的。
例如,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
Run Code Online (Sandbox Code Playgroud)
为什么我们不能改变参数的位置ldd
?
一些 GNU 实用程序会默默地重新组织命令行参数,以便选项和选项参数位于操作数之前。这不是标准行为。
符合标准的实用程序期望选项和选项参数首先出现,并且当命令行解析器找到第一个非选项参数时,其余参数被视为操作数:
cp -i file1 file2
Run Code Online (Sandbox Code Playgroud)
在上面,第一个参数是一个选项,而最后两个参数是操作数。
cp file1 file2 -i
Run Code Online (Sandbox Code Playgroud)
上面有三个操作数,一个非 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
Run Code Online (Sandbox Code Playgroud)
或者你可以使用--
来明确地标记选项的结束(这会工作的命令是否解析其选项的GNU方式与否):
$ cp -- file1 file2 -i
cp: target '-i' is not a directory
Run Code Online (Sandbox Code Playgroud)
在以下方面需要牢记这一点:
grep 'PATTERN' *.txt
Run Code Online (Sandbox Code Playgroud)
使用 GNU,grep
您需要编写:
grep -- 'PATTERN' *.txt
Run Code Online (Sandbox Code Playgroud)
或者
grep -e 'PATTERN' -- *.txt
Run Code Online (Sandbox Code Playgroud)
如果PATTERN
某些.txt
文件的或 名称以-
.
您的ldd
(在 GNU 系统上是一个bash
手动解析选项的脚本,不使用 GNU getopt_long()
API)没有以“GNU 方式”解析其命令行参数,这(恕我直言)它是正确的。
来自 GNU 文档getopt_long(3)
:
默认情况下,
getopt()
在argv
扫描时置换 的内容,以便最终所有非选项都在最后。[...] 如果optstring
is的第一个字符+
或POSIXLY_CORRECT
设置了环境变量,则一旦遇到非选项参数,选项处理就会停止。