Могу ли я импортировать переменные в R из глобального файла? - PullRequest
0 голосов
/ 25 июня 2019

Я интегрирую скрипт 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" и file как "./here /is/a/path/file.csv".

Ответы [ 2 ]

1 голос
/ 25 июня 2019

Если можно заменить скобки скобками, то 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)
1 голос
/ 25 июня 2019

Если в файле .mk есть что-то, кроме прямого расширения переменных (например, более сложные make -rules / tricks / functions), может быть лучше доверять make, чтобы выполнить расширение за вас, а затемпрочитайте его. Есть сообщение здесь , которое, как я обнаружил, сбрасывает все переменные (после обработки).

TL; DR

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.


В блоге предлагается использовать фальшивую цель

.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 -to-envvar - лучший способ для вас, нетрудно перенаправить вывод этого вызова make в другой файл, разобрать соответствующие строки,и затем сделайте readRenviron для этого нового файла.Это кажется более косвенным из-за использования двух временных файлов, но они очищены, поэтому не о чем беспокоиться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...