这是一个容易犯的错误。
首先,让我们定义一些术语:
-
语句 这是一段 shell 代码,通常代表 shell 执行的单个操作。该操作可以是文档化的 shell 内置或关键字命令加参数、外部可执行文件的文件名加参数、复合命令(例如大括号块或子shell)、上述所有内容的管道或命令列表上述所有的。多条语句通常可以使用语句分隔符按顺序编码,这由 shell 不同。例如,Unix
bash shell 使用分号(用于前台执行)或 & 符号(用于后台),而 Windows cmd shell 使用 & 符号(用于前台)。
-
command 这是一个非常笼统的术语,可以指代上述任何类型的命令,也可以指整个语句,甚至可以指多个连续的语句。这是一种需要上下文来阐明其含义的术语。
-
简单命令 这是一个仅执行 shell 内置或外部可执行文件的命令。它们可能作为它们自己的语句出现,或者它们可能构成复合命令、管道或命令列表的一部分。在 bash shell 中,变量赋值和重定向可以构成一个简单命令的一部分,甚至是整个命令。
-
命令字 在单个简单命令的上下文中,这是您要运行的程序的名称.这将是内置 shell 的文档名称,或者是外部可执行文件的文件名。这有时被描述为命令的第一个单词,或第零个参数。
-
命令参数 在单个简单命令的上下文中,这是给定的零个或多个(附加)参数到内置或可执行文件。
-
命令行 这个术语暗示它指的是一个单行的shell代码。然而,它通常稍微松散地用于描述任何独立的、通常是一次性的 shell 代码,实际上可能包含换行符,因此从技术上讲,它包含不止一个文本行。 command 一词有时也用作此概念的简写,进一步增加了它的歧义。另请注意,命令行 有时用作command-line interface 类型的用户界面的简写,不限定术语command 绝不意味着。
-
系统命令 这是另一个需要上下文来阐明其含义的通用术语。它可以被认为是 command 的同义词,除了附加修饰符“system”表明命令的执行是从存在于 shell 之外的编程上下文中启动的,例如 R 会话。
system2() 函数的设计似乎表明作者只打算将其用于运行简单命令。它将命令词作为第一个函数参数(预期为标量字符串,表示单元素字符向量)和命令参数 作为第二个(也应该是一个字符向量,零个或多个元素)。以下是文档在这两个函数参数的描述中的说明:
command
要调用的系统命令,作为字符串。
args
command 的参数字符向量。
上面说的不是很清楚,但是详细信息部分的第一句话有帮助:
与system() 不同,command 总是被shQuote() 引用,因此它必须是没有参数的单个命令。
如您所见,文档有点模糊,因为它围绕通用术语 command 没有太多说明。他们还使用模糊的术语系统命令,这也无济于事。他们的意思是第一个函数参数command 旨在成为简单命令的命令字 >。如果您想传递任何命令参数,您必须在第二个函数参数args 中指定它们。
在作者的辩护中,shell 代码可能非常依赖于平台,并且在实现和行为上不一致。使用我在这篇文章中定义的更精确的术语会使文档编写者面临犯错误的风险,至少对于 R 渴望支持的某些系统而言。模糊性可以成为避免完全错误风险的避风港。
请注意,这与其他 R 系统命令函数 system() 不同:
command
要调用的系统命令,作为字符串。
在详细信息部分:
command 被解析为命令加上以空格分隔的参数。因此,如果命令的路径(或单个参数,例如文件路径)包含空格,则必须引用它,例如通过shQuote()。 Unix-likes 将命令行传递给 shell(通常是 '/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)@987654350 @command 对其第一个命令参数的插值。我们需要printf 来插值最终的\n ASCII 字符代码。)
另外,应该注意的是,虽然system2() 明确鼓励只运行简单命令,通过强制分隔命令词 em> 和 command arguments 转换成单独的函数参数,很有可能颠覆这种意图并使用 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
当然,这是非常不可取的。