这是一个容易犯的错误。
首先,让我们定义一些术语:
- 语句 这是一段 shell 代码,通常代表 shell 要执行的单个操作。该操作可以是文档化的 shell 内置或关键字命令加参数、外部可执行文件的文件名加参数、复合命令(例如大括号块或子shell)、上述所有内容的管道或命令列表上述所有的。多条语句通常可以使用语句分隔符按顺序编码,这由 shell 不同。例如,Unix
bash
shell 使用分号(用于前台执行)或 & 号(用于后台),而 Windowscmd
shell 使用 & 号(用于前台)。
- command 这是一个非常笼统的术语,可以指上述任何类型的命令,也可以指整个语句,甚至可以指多个连续的语句。这是一种需要上下文来阐明其含义的术语。
- 简单命令 这是一个仅执行 shell 内置或外部可执行文件的命令。它们可能作为它们自己的语句出现,或者它们可能构成复合命令、管道或命令列表的一部分。在 bash shell 中,变量赋值和重定向可以构成一个简单命令的一部分,甚至是整个命令。
- 命令字 在单个简单命令的上下文中,这是您要运行的程序的名称。这将是内置 shell 的文档名称,或者是外部可执行文件的文件名。这有时被描述为命令的第一个字,或第零个参数。
- 命令参数 在单个简单命令的上下文中,这是给内置或可执行文件的零个或多个(附加)参数。
- 命令行 这个术语暗示它指的是一行shell 代码。然而,它通常稍微松散地用于描述任何独立的、通常是一次性的 shell 代码,实际上可能包含换行符,因此从技术上讲,它包含不止一个文本行。术语命令有时也被用作这个概念的简写,进一步增加了它的歧义。另请注意,命令行有时用作用户界面的命令行界面类型的简写,不合格的术语command绝不意味着。
- 系统命令 这是另一个需要上下文来阐明其含义的通用术语。它可以被认为是command的同义词,除了附加修饰符“system”表明命令的执行是从存在于 shell 之外的编程上下文(例如 R 会话)启动的。
该system2()
函数的设计似乎表明作者只打算将其用于运行简单的命令。它将命令词作为第一个函数参数(预期为标量字符串,表示单元素字符向量),将命令参数作为第二个函数参数(也应为字符向量,零个或多个元素)。以下是文档在这两个函数参数的描述中的说明:
command
要调用的系统命令,作为字符串。
args
的参数的字符向量command
。
上面并没有说得很清楚,但是详细信息部分的第一句话有帮助:
不像system()
,command
总是被 引用shQuote()
,所以它必须是一个不带参数的命令。
如您所见,文档有点含糊,因为它在没有太多说明的情况下抛出了通用术语命令。他们还使用模糊的术语system command,这也无济于事。他们的意思是第一个函数参数command
是一个简单命令的命令字。如果要传递任何命令参数,则必须在第二个函数参数中指定它们。args
在作者的辩护中,shell 代码可能非常依赖于平台并且在实现和行为上不一致。使用我在这篇文章中定义的更精确的术语会使文档编写者面临犯错误的风险,至少对于 R 渴望支持的某些系统而言。模糊性可以成为抵御彻底错误风险的避风港。
请注意,这与其他 R 系统命令功能不同system()
:
command
要调用的系统命令,作为字符串。
在详细信息部分:
command
被解析为命令加上以空格分隔的参数。因此,如果命令的路径(或单个参数,如文件路径)包含空格,则必须将其引用,例如shQuote()
. Unix-likes 将命令行传递给 shell(通常是 '<code>/bin/sh',而 POSIX 需要那个 shell),所以command
可以是 shell 认为可执行的任何东西,包括 shell 脚本,它可以包含多个分隔的命令由;
.
所以对于system()
,第一个函数参数command
是一个完整的命令行。
因此它们实际上使用完全相同的函数参数名称 ( command
) 和描述(“要调用的系统命令,作为字符串。”),即使参数在system()
和之间有两个完全不同的含义system2()
!理解这个文档确实需要读者仔细解析。
所以,最后,我们可以理解如何正确使用system2()
来调用想要的java命令了:
word <- 'java';
args <- c('-jar','sample.jar','674');
result <- system2(word,args,stdout='C:/Code/stdout.txt',stderr='C:/Code/stderr.txt');
只是为了进一步澄清,通过尝试一些简单的测试用例来试验这些函数的行为是有帮助的。例如(在我的 Cygwin bash shell 上):
system('printf %d:%x\\\\n 31 31');
## 31:1f
system2('printf',c('%d:%x\\\\n','31','31'));
## 31:1f
(请注意,反斜杠的四倍是必要的,因为它们通过 3 个插值上下文,即 (1) R 字符串文字插值,(2) bash(非单引号)词法上下文,以及 (3)printf
命令的第一个插值命令参数。我们需要printf
插入最终的\n
ASCII 字符代码。)
此外,应该注意的是,虽然通过强制将命令字和命令参数system2()
分离为单独的函数参数来明确鼓励只运行简单命令,但很有可能破坏这种意图并使用 shell 元字符来执行一些明显不简单的 shell通过接口代码:system2()
system('echo a b; echo c d');
## a b
## c d
system2('echo',c('a','b; echo c d'));
## a b
## c d
当然,这是非常不可取的。