这是一个容易犯的错误。
首先,让我们定义一些术语:
-
陈述这是一段 shell 代码,通常表示 shell 要执行的单个操作。该操作可以是记录的shell内置命令或关键字加参数,外部可执行文件的文件名加参数,复合命令(例如大括号块或子shell),上述所有内容的管道,或上述所有内容的命令列表。通常可以使用语句分隔符按顺序对多个语句进行编码,这些分隔符因 shell 而异。例如,Unix 外壳程序使用分号(用于前台执行)或 & 符号(用于背景),而 Windows 外壳程序使用 & 符号(用于前景)。
bash
cmd
-
命令这是一个非常通用的术语,可以指上述任何类型的命令,或整个语句,甚至多个顺序语句。这是那种需要上下文来澄清其含义的术语。
-
简单命令这是一个仅执行 shell 内置或外部可执行文件的命令。这些语句可以作为它们自己的语句出现,也可以构成复合命令、管道或命令列表的一部分。在 bash shell 中,变量赋值和重定向可以构成简单命令的一部分,甚至是整个命令。
-
命令字在单个简单命令的上下文中,这是要运行的程序的名称。这将是 shell 内置的书面名称,或者是外部可执行文件的文件名。这有时被描述为命令的第一个单词,或第零个参数。
-
命令参数在单个简单命令的上下文中,这是提供给内置或可执行文件的零个或多个(附加)参数。
-
命令行这个术语带有它指的是一行shell代码的建议。但是,它通常使用得稍微宽松一些,来描述任何独立的,通常是一次性的shell代码,这些shell代码实际上可能包含换行符,因此从技术上讲由多个文本行组成。术语命令有时也用作此概念的简写,这进一步增加了其模糊性。另请注意,命令行有时用作用户界面的命令行界面类型的简写,这从不由非限定术语命令表示。
-
系统命令这是另一个需要上下文来澄清其含义的通用术语。它可以被视为命令的同义词,除了附加修饰符“system”表示命令的执行是从 shell 外部存在的编程上下文(如 R 会话)启动的。
system2()
函数的设计似乎表明作者只打算用它来运行简单的命令。它将命令词作为第一个函数参数(预期为标量字符串,表示一个单元素字符向量),并将命令参数作为第二个(也应为字符向量,零个或多个元素)。以下是文档在这两个函数参数的描述中的位置:
command
要调用的系统命令,作为字符串。
args
参数的字符向量。command
以上并没有使它完全清楚,但详细信息部分的第一句话有所帮助:
与 不同,总是由 引用,所以它必须是一个没有参数的命令。system()
command
shQuote()
如您所见,文档有点模糊,因为它抛出了一般术语命令,没有太多的澄清。他们还使用模糊的术语系统命令,这也无济于事。它们的意思是,第一个函数参数旨在成为简单命令的命令字。如果要传递任何命令参数,则必须在第二个函数参数中指定它们。command
args
在作者的辩护中,shell代码可能非常依赖于平台,并且在实现和行为上不一致。使用我在这篇文章中定义的更精确的术语会使文档编写者面临犯错误的风险,至少对于R希望支持的一些系统而言。模糊性可以成为防止完全错误风险的安全屋。
请注意,这与其他 R 系统命令函数 system() 不同
:
command
要调用的系统命令,作为字符串。
在“详细信息”部分中:
command
被解析为命令加上由空格分隔的参数。因此,如果命令的路径(或单个参数,如文件路径)包含空格,则必须将其引用,例如由 .类Unix将命令行传递给shell(通常为'',POSIX需要该shell),因此可以是shell视为可执行的任何内容,包括shell脚本,并且可以包含由.shQuote()
/bin/sh
command
;
所以对于 ,第一个函数参数是一个完整的命令行。system()
command
因此,它们实际上使用完全相同的函数参数名称 () 和描述(“要调用的系统命令,作为字符串”),即使该参数在 和 之间有两个完全不同的含义!理解本文档确实需要读者仔细解析。command
system()
system2()
因此,最后,我们可以了解如何正确使用来调用所需的java命令:system2()
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)命令对其第一个命令参数的插值。我们需要插值最终的 ASCII 字符代码。printf
printf
\n
另外,应该注意的是,尽管通过将命令字和命令参数强制分离为单独的函数参数来明确鼓励仅运行简单的命令,但很有可能颠覆这一意图并使用shell元字符通过接口执行一些绝对不简单的shell代码:system2()
system2()
system('echo a b; echo c d');
## a b
## c d
system2('echo',c('a','b; echo c d'));
## a b
## c d
当然,这是非常不可取的。