我正在集成一个R脚本,以将一些图形生成到与Makefile一起拉到的更大项目中。在这个更大的项目中,我有一个名为globals.mk
的文件,其中包含该项目中许多其他脚本使用的全局变量。例如,我要运行的仿真数量是我要在此R脚本中使用的全局数量。我可以将其“导入”为变量,还是必须在R脚本中手动定义每个变量?
编辑:这是我需要阅读的全局变量的示例。
num = 100
path = ./here/is/a/path
file = $(path)/file.csv
我希望R脚本将变量num
设置为100(或“ 100”),将path
设置为“ ./here/is/a/path”和{{1} }作为“ ./here/is/a/path/file.csv”。
答案 0 :(得分:1)
如果.mk
文件除了直接变量扩展以外(例如更复杂的make
规则/技巧/功能)没有其他用途,最好信任make
来执行扩展,然后阅读。我发现有一条帖子here(在处理后)转储了所有变量内容。
expand_mkvars <- function(path, aslist = FALSE) {
stopifnot(file.exists(mk <- Sys.which("make")))
tf <- tempfile(fileext = ".mk")
# needed on my windows system
tf <- normalizePath(tf, winslash = "/", mustWork = FALSE) # tempfile should suffice
on.exit(suppressWarnings(file.remove(tf)), add = TRUE)
writeLines(c(".PHONY: printvars",
"printvars:",
"\t@$(foreach V,$(sort $(.VARIABLES)), \\",
"\t $(if $(filter-out environment% default automatic, \\",
"\t $(origin $V)),$(warning $V=$($V))))"), con = tf)
out <- system2(mk, c("-f", shQuote(path), "-f", shQuote(tf), "-n", "printvars"),
stdout = TRUE, stderr = TRUE)
out <- out[grepl(paste0("^", tf), out)]
out <- gsub(paste0("^", tf, ":[0-9]+:\\s*"), "", out)
known_noneed <- c(".DEFAULT_GOAL", "CURDIR", "GNUMAKEFLAGS", "MAKEFILE_LIST", "MAKEFLAGS")
out <- out[!grepl(paste0("^(", paste(known_noneed, collapse = "|"), ")="), out)]
if (aslist) {
spl <- strsplit(out, "=")
nms <- sapply(spl, `[[`, 1)
rest <- lapply(spl, function(a) paste(a[-1], collapse = "="))
setNames(rest, nms)
} else out
}
实际情况:
expand_mkvars("~/StackOverflow/karthikt.mk")
# [1] "file=./here/is/a/path/file.csv" "num=100"
# [3] "path=./here/is/a/path"
expand_mkvars("~/StackOverflow/karthikt.mk", aslist = TRUE)
# $file
# [1] "./here/is/a/path/file.csv"
# $num
# [1] "100"
# $path
# [1] "./here/is/a/path"
我尚未在其他系统上进行测试,因此您可能需要调整known_noneed
以添加弹出的其他变量。根据您的需求,您也许可以进行更智能的过滤(例如,您的所有变量都不以大写字母开头),但是在本示例中,我将其保留在make
是已知且不需要的变量中给我们。
blog post建议使用虚假目标
.PHONY: printvars
printvars:
@$(foreach V,$(sort $(.VARIABLES)), \
$(if $(filter-out environment% default automatic, \
$(origin $V)),$(warning $V=$($V))))
(有些是制表符,不是所有空格,对make
非常重要)
不幸的是,它产生的输出超出您的技术要求:
$ /c/Rtools/bin/make.exe -f ~/StackOverflow/karthikt.mk printvars
C:/Users/r2/StackOverflow/karthikt.mk:10: .DEFAULT_GOAL=all
C:/Users/r2/StackOverflow/karthikt.mk:10: CURDIR=/Users/r2/Projects/Ford/shiny/shinyobjects/inst
C:/Users/r2/StackOverflow/karthikt.mk:10: GNUMAKEFLAGS=
C:/Users/r2/StackOverflow/karthikt.mk:10: MAKEFILE_LIST= C:/Users/r2/StackOverflow/karthikt.mk
C:/Users/r2/StackOverflow/karthikt.mk:10: MAKEFLAGS=
C:/Users/r2/StackOverflow/karthikt.mk:10: SHELL=sh
C:/Users/r2/StackOverflow/karthikt.mk:10: file=./here/is/a/path/file.csv
C:/Users/r2/StackOverflow/karthikt.mk:10: num=100
C:/Users/r2/StackOverflow/karthikt.mk:10: path=./here/is/a/path
make: Nothing to be done for 'printvars'.
因此,我们需要进行一些过滤,以便对函数中的大部分代码进行操作。
编辑:readRenviron
到envvar是最适合您的方法,将make
调用的输出重定向到另一个文件并不困难,解析出相关的行,然后对该新文件执行readRenviron
。由于使用了两个临时文件,因此似乎更加间接,但是已将它们清除,因此不必担心。
答案 1 :(得分:1)
如果可以用括号将括号括起来,那么readRenviron
将读取此类文件并执行替换,将内容作为环境变量返回。
# write out test file globals2.mk which uses brace brackets
Lines <- "num = 100
path = ./here/is/a/path
file = ${path}/file.csv"
cat(Lines, file = "globals2.mk")
readRenviron("globals2.mk")
Sys.getenv("num")
## [1] "100"
Sys.getenv("path")
## [1] "./here/is/a/path"
Sys.getenv("file")
## [1] "./here/is/a/path/file.csv"
如果重要的是使用括号而不是括号,请读取globals.mk,将括号替换为括号,然后再次写出文件。
# write out test file - this one uses parentheses as in question
Lines <- "num = 100
path = ./here/is/a/path
file = $(path)/file.csv"
cat(Lines, file = "globals.mk")
# read globals.mk, perform () to {} substitutions, write out and then re-read
tmp <- tempfile()
L <- readLines("globals.mk")
cat(paste(chartr("()", "{}", L), collapse = "\n"), file = tmp)
readRenviron(tmp)