R - 通过管道连接脚本

时间:2013-07-30 16:37:29

标签: r unix pipe

我有许多R脚本,我想使用UNIX风格的管道链接在一起。每个脚本都将数据帧作为输入,并提供数据帧作为输出。例如,我想象这样会在R的批处理模式下运行。

  cat raw-input.Rds | step1.R | step2.R | step3.R | step4.R > result.Rds

有关如何做到这一点的任何想法?

3 个答案:

答案 0 :(得分:4)

编写可执行脚本并不困难,如何从文件和/或管道中读取脚本是多么棘手。我在这里写了一个有点通用的函数:https://stackoverflow.com/a/15785789/1201032

以下是I / O采用csv文件形式的示例:

您的step?.R文件应如下所示:

#!/usr/bin/Rscript

OpenRead <- function(arg) {

   if (arg %in% c("-", "/dev/stdin")) {
      file("stdin", open = "r")
   } else if (grepl("^/dev/fd/", arg)) {
      fifo(arg, open = "r")
   } else {
      file(arg, open = "r")
   }
}

args  <- commandArgs(TRUE)
file  <- args[1]
fh.in <- OpenRead(file)

df.in <- read.csv(fh.in)
close(fh.in)

# do something
df.out <- df.in

# print output
write.csv(df.out, file = stdout(), row.names = FALSE, quote = FALSE)

并且您的csv输入文件应如下所示:

col1,col2
a,1
b,2

现在这应该有效:

cat in.csv | ./step1.R - | ./step2.R -

-很烦人但很有必要。还要确保运行类似chmod +x ./step?.R的内容以使脚本可执行。最后,您可以将它们(并且没有扩展名)存储在您添加到PATH的目录中,这样您就可以像这样运行它:

cat in.csv | step1 - | step2 -

答案 1 :(得分:3)

为什么在整个R环境可用时,你想要将工作流程塞进管道中是不可能的。

制作一个包含以下内容的main.r

source("step1.r")
source("step2.r")
source("step3.r")
source("step4.r")

就是这样。您不必将每个步骤的输出转换为序列化格式;相反,您可以保留所有R对象(数据集,拟合模型,预测值,格子/ ggplot图形等),为下一步处理做好准备。如果内存有问题,您可以在每个步骤结束时rm任何不需要的对象;或者,每个步骤都可以使用它在完成后删除的environment,首先将所有必需的对象导出到全局环境。


如果需要模块化代码,您可以按如下方式重新设定工作流程。将每个文件完成的工作封装到一个或多个函数中。然后使用适当的参数在main.r中调用这些函数。

source("step1.r")  # defines step1_read_input, step1_f2
source("step2.r")  # defines step2_f2
source("step3.r")  # defines step3_f1, step3_f2, step3_f3
source("step4.r")  # defines step4_write_output

step1_read_input(...)
step1_f2(...)
....
step4write_output(...)

答案 2 :(得分:0)

您需要在每个脚本的顶部添加一行,以便从stdin读入。通过this answer

in_data <- readLines(file("stdin"),1)

您还需要将每个脚本的输出写入stdout()