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