有人曾经告诉我,在解析命令行上的选项时有一个标准。就像是:
./script.sh [options/flags] [command or file]
Run Code Online (Sandbox Code Playgroud)
我知道在解析 shell 脚本时这会让生活更轻松,因为您可以shift
通过标志并且可以访问任何剩余的东西$@ or $*
,但是是否有实际的书面标准?
我看大多数程序遵循这个标准,但也有一些例外,例如,ls
其中ls -l /path
,ls /path -l
和ls /path -l /path2
都是可以接受的。
POSIX 基本定义有一节关于“实用程序约定”,它适用于 POSIX 基本实用程序。
在解析 shell 脚本或 C 程序中的命令行时,标准getopts
实用程序和getopt()
系统接口(“C 函数”)遵循准则(在上面链接的页面上的进一步下方)。具体来说,对于getopts
(例如):
当遇到选项结束时,
getopts
实用程序应以大于零的返回值退出;shell 变量OPTIND
应设置为第一个操作数的索引,"$#" +1
如果没有操作数,则为该值;该name
变量应设置为的字符。以下任何一项都应标识选项的结束:第一个--
不是选项参数的参数,找到不是选项参数且不以 a 开头的参数-
,或遇到错误。
这基本上是说选项应该先出现,然后是操作数(你的“命令或文件”)。
以任何其他方式执行它都会导致使用getopts
或getopt()
不可能,并且还可能使习惯于为命令指定选项和操作数的 POSIX 方式的用户感到困惑。
请注意,上述标准仅适用于 POSIX 实用程序,但因此它通常为 Unix 实用程序设置了优先级。显然,非标准 Unix 实用程序可以选择遵循或打破这一点。
例如,GNU coreutils,即使它们实现了标准实用程序,也允许诸如
$ ls Documents/ -l
Run Code Online (Sandbox Code Playgroud)
如果POSIXLY_CORRECT
未设置环境变量,而相同实用程序的 BSD 版本则没有。
这导致以下在 BSD 系统上按预期工作(如果您期望 POSIX 行为,即):
$ touch -- 'test' '-l'
$ ls -l test -l
-rw-r--r-- 1 kk kk 0 Jan 11 16:44 -l
-rw-r--r-- 1 kk kk 0 Jan 11 16:44 test
Run Code Online (Sandbox Code Playgroud)
但是在 GNU coreutils 系统上,你会得到
$ ls -l test -l
-rw-r--r-- 1 kk kk 0 Jan 11 16:44 test
Run Code Online (Sandbox Code Playgroud)
然而:
$ env POSIXLY_CORRECT=1 ls -l test -l
Run Code Online (Sandbox Code Playgroud)
和
$ ls -l -- test -l
Run Code Online (Sandbox Code Playgroud)
也会在 GNU 系统上做“正确”的事情。