Unix shell命令的一般语法是什么?

13

为什么有时候一些命令的选项前会有一个+符号,而有时候会有一个-符号?

例如:

sort -f
sort -nr
sort +4n
sort +3nr

8
历史、便利、常识,有时候也会有一些糟糕的决策(dd,我在看着你!) - Alok Singhal
1
@eSKay:别忘了单破折号长选项和双破折号长选项。而且为了更加有趣,less 使用 -+ 来将环境变量选项覆盖回它们的默认值,但对于大多数程序而言,命令行选项始终优先于环境变量。一些 ps 版本支持带破折号的选项,而另一些则不支持。GNU ps 支持两种方式。 - Dennis Williamson
4个回答

26
这些天,使用getopt()(也称为getopt(3))的POSIX标准被广泛地作为标准符号使用,但在早期,人们正在进行实验。在某些机器上,sort命令不再支持+符号。然而,各种命令(特别是artar)接受没有任何前缀字符的控制 - 而dd(Alok在评论中提到)则使用另一种约定。

GNU约定使用'--'表示长选项(由getopt_long(3)支持),这已经从使用'+'改变了。当然,X11软件在多字符选项之前使用单破折号。因此,整个事情都是历史遗物的集合,因为人们试验了如何最好地处理它。

POSIX记录了它所遵循的Utility Conventions,除非历史先例更强。


有哪些选项处理的样式?

[曾经,SO 367309 包含以下材料作为我的答案。它最初由FerranB在2008年12月15日02:02提出,但随后被关闭和删除。]

你认识多少种不同类型的选项?我能想到许多,包括:

  • 单个字母选项以单破折号为前缀,在没有参数时可以分组,参数可以附加到选项字母或下一个参数(许多Unix命令;大多数POSIX命令)。
  • 单个字母选项以单破折号为前缀,不允许分组,参数必须附加(RCS)。
  • 单个字母选项以单破折号为前缀,不允许分组,参数必须分离(早期的POSIX SCCS,我很确定)。
  • 多个字母选项以单破折号为前缀,参数可以附加或在下一个参数中(X11程序;还有许多具有NeXTSTEP遗产的Mac OS X上的Java程序和其他程序)。
  • 多个字母选项以单破折号为前缀,可以缩写(Atria Clearcase)。
  • 多个字母选项以单加号为前缀(已废弃)。
  • 多个字母选项以双破折号为前缀;参数可以跟随'='或分离(GNU实用程序)。
  • 没有前缀/后缀的选项,有些名称有缩写或被暗示,参数必须分离。 (AmigaOS Shell
对于那些带有可选参数的选项,有时必须将参数附加在一起(co -p1.3 rcsfile.c),有时必须跟随一个'='符号。 POSIX 无法有意义地支持可选参数(POSIX getopt() 仅允许它们出现在命令行上的最后一个选项中)。
所有明智的选项系统都使用由双破折号('--')组成的选项来表示“选项结束”——以下参数是“非选项参数”(通常是文件名;POSIX 将它们称为“操作数”),即使它们以连字符开头。(我认为支持这种表示法是必要的。请注意,如果 -- 前面有一个需要参数的选项,则 -- 将被视为该选项的参数,而不是“选项结束”标记。)
许多但并非所有程序都接受单个破折号作为文件名,表示标准输入(通常)或标准输出(偶尔)。有时,如 GNU 'tar',两者可以在单个命令行中使用:
... | tar -cf - -F - | ...

第一个单独的短横线表示“写入标准输出”; 第二个表示“从标准输入读取文件名”。

一些程序使用其他约定,即不以短横线为前缀的选项。其中许多来自Unix最早的日子。例如,“tar”和“ar”都接受没有短横线的选项,因此:

tar cvzf /tmp/somefile.tgz some/directory

dd 命令专门使用 opt=value

dd if=/some/file of=/another/file bs=16k count=200

一些程序允许您完全交错选项和其他参数;C编译器、make和运行在没有POSIXLY_CORRECT环境的GNU实用程序就是例子。许多程序希望选项在其他参数之前出现。
请注意,git和其他版本控制系统命令通常使用混合系统:
git commit -m 'This is why it was committed'

有一个子命令作为参数之一。通常,在命令和子命令之间可以指定可选的“全局”选项。POSIX 中有这种情况的例子; sccs 命令属于此类别; 你可以认为运行其他命令的某些命令也属于此类别: POSIX 中的 nicexargs 可以想到; sudo 是一个非 POSIX 的例子,同样还有 svncvs


我对不同系统没有强烈的偏好。当可选项较少时,具有助记价值的单个字母是方便的。GNU支持此功能,但建议使用双破折线前缀的多字母选项进行备份。

我反对的一些事情。最糟糕的之一是相同的选项字母在取决于先前出现的其他选项字母而具有不同的含义。在我的书中,这是不可以的,但我知道有些软件会这样做。

另一个令人反感的行为是处理参数的风格不一致(特别是对于单个程序,但也适用于一套程序)。要么需要附加的参数,要么需要分离的参数(或允许任何一种),但不要使某些选项需要附加参数,而其他选项需要分离参数。并且请始终注意是否可以使用“=”来分隔选项和参数。

与许多(与软件相关的)事物一样-一致性比个体决策更重要。使用自动化和标准化参数处理工具有助于保持一致性。


无论你做什么,请务必阅读TAOUP的命令行选项并考虑命令行界面标准。(由J F Sebastian添加 - 感谢;我同意。

11
man --help命令会将长选项--help传递给man。而man -help则会将四个选项-h-e-l-p传递给man。可能man会查看第一个选项-h,并打印帮助信息并退出。但是每个命令解释命令行参数的方式都不同。 - Alok Singhal
@eSKay:正如Alok所说,这取决于命令。许多X11命令使用单破折号带有长参数;这些命令不允许选项分组。其他命令(使用经典的getopt())将所有选项字母视为单个选项;如果选项不需要参数,则可以在群集中跟随另一个选项。也就是说,这可能是您的机器上'man'命令正在执行的操作。或者,它可能将“--help”识别为长选项,并将“-h”识别为短选项,立即处理它,而不检查下一个字母“e”是否是有效选项。这取决于命令。 - Jonathan Leffler
@JonathanLeffler 你可以考虑将 test[ 添加到你的列表中,我认为它们是唯一需要其最后一个参数为 ] 的命令。 - Mark Setchell
1
很好的回答。值得一提的是,POSIX术语“操作数”指的是您所称的“非选项参数”。java和具有NeXTSTEP遗产的OSX / Darwin实用程序(我假设)也使用由单破折号前缀的多字母选项。还值得一提的是(非POSIX)概念“子命令”,正如git示例所示。 - mklement0
1
@mklement0:谢谢。我已经采纳了您的建议。 - Jonathan Leffler
显示剩余2条评论

5

这是完全任意的;命令可能会以其特殊的方式实现所有选项处理,也可能调用其他方便函数。 getopt() 函数族非常受欢迎,因此即使是最近编写的软件也遵循这些例程设置的惯例。 当然,总有例外!


2

因此,解析选项的工作留给了应用程序,这就导致了不一致性。以您提供的排序示例为例,以下是coreutils中等效的写法:

sort -k3
sort --k 3
sort --key 3
sort --key=3
_POSIX2_VERSION=199209 sort +2

2
一个 shell 命令只是一个程序,它可以自由地解释其命令行。Unix 从未像苹果那样设立接口警察来确保命令行界面在不同应用程序中的一致性。因此,在旧命令中存在不一致性。
展望未来,我认为命令行工具将逐渐向 GNU 标准迁移,包括双破折号等。 (我习惯于使用单破折号,并且仍然觉得双破折号非常尴尬,但它很一致。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接