Rscript: определить путь к исполняемому скрипту
У меня есть скрипт foo.R
это включает в себя другой сценарий other.R
, который находится в том же каталоге:
#!/usr/bin/env Rscript
print("Hello")
source("other.R")
Но я хочу R
чтобы найти это other.R
независимо от того, какой текущий рабочий каталог.
Другими словами, foo.R
Нужно знать свой собственный путь. Как я могу это сделать?
31 ответ
Здесь есть простое решение проблемы. Эта команда:
script.dir <- dirname(sys.frame(1)$ofile)
возвращает путь к текущему файлу скрипта. Работает после сохранения скрипта.
Вы можете использовать commandArgs
функция, чтобы получить все опции, которые были переданы Rscript фактическому интерпретатору R, и найти их --file=
, Если ваш сценарий был запущен с пути или если он был запущен с полным путем, script.name
ниже начнется с '/'
, В противном случае оно должно быть относительно cwd
и вы можете соединить два пути, чтобы получить полный путь.
Изменить: звучит так, как будто вам нужно только script.name
выше и скинуть последний компонент пути. Я удалил ненужное cwd()
образец и почистил основной скрипт и выложил мой other.R
, Просто сохраните этот скрипт и other.R
скрипт в тот же каталог, chmod +x
их и запустить основной скрипт.
main.R:
#!/usr/bin/env Rscript
initial.options <- commandArgs(trailingOnly = FALSE)
file.arg.name <- "--file="
script.name <- sub(file.arg.name, "", initial.options[grep(file.arg.name, initial.options)])
script.basename <- dirname(script.name)
other.name <- file.path(script.basename, "other.R")
print(paste("Sourcing",other.name,"from",script.name))
source(other.name)
другое.Р:
print("hello")
вывод:
burner@firefighter:~$ main.R
[1] "Sourcing /home/burner/bin/other.R from /home/burner/bin/main.R"
[1] "hello"
burner@firefighter:~$ bin/main.R
[1] "Sourcing bin/other.R from bin/main.R"
[1] "hello"
burner@firefighter:~$ cd bin
burner@firefighter:~/bin$ main.R
[1] "Sourcing ./other.R from ./main.R"
[1] "hello"
Это то, что я считаю, что Дехманн ищет.
Я не мог заставить решение Suppressingfire работать при "исходном" режиме с консоли R.
Я не мог заставить решение Хадли работать при использовании Rscript.
Лучшее из обоих миров?
thisFile <- function() {
cmdArgs <- commandArgs(trailingOnly = FALSE)
needle <- "--file="
match <- grep(needle, cmdArgs)
if (length(match) > 0) {
# Rscript
return(normalizePath(sub(needle, "", cmdArgs[match])))
} else {
# 'source'd via R console
return(normalizePath(sys.frames()[[1]]$ofile))
}
}
frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])
Не спрашивайте меня, как это работает, потому что я забыл:/
Это работает для меня
library(rstudioapi)
rstudioapi::getActiveDocumentContext()$path
Ответ rakensi из Getting path of R script является наиболее правильным и действительно блестящим ИМХО. Тем не менее, это все еще хак, включающий фиктивную функцию. Я цитирую это здесь, чтобы другим было легче его найти.
sourceDir <- getSrcDirectory (function (dummy) {dummy})
Это дает каталог файла, в который был помещен оператор (где определена фиктивная функция). Затем его можно использовать для установки рабочего каталога и использования относительных путей, например
setwd(sourceDir)
source("other.R")
или создать абсолютные пути
source(paste(sourceDir, "/other.R", sep=""))
Я сделал для этого пакет с 03.12.2020, доступный на CRAN, под названием "this.path".
Установите его, используя:
install.packages ("this.path")
а затем используйте его:
this.path::this.path()
или же
библиотека (this.path)
this.path()
У меня все еще есть исходный ответ ниже, хотя он менее функциональный, чем версия в пакете. В Unix-подобных ОС странные символы (такие как " ") в аргументе командной строки 'файл'Rscript заменяются (например, "~+~"). R делает это для того, чтобы было проще использовать это имя файла для других системных команд, но это не то, что мы хотим. Учитывая, что мы хотим использовать путь в R, любые такие странные последовательности символов должны быть заменены.
Оригинальный ответ:
Мой ответ - это улучшение ответа Джерри Т. Проблема, которую я обнаружил, заключается в том, что он угадывает,
source
вызов был сделан путем проверки наличия переменной
ofile
находится в первом кадре в стеке. Это не будет работать ни с вложенными исходными вызовами, ни с исходными вызовами, сделанными из неглобальной среды. Кроме того, перед проверкой аргументов командной строки необходимо искать исходный вызов, что также было исправлено. Вот мое решение:
this.path <- function (verbose = getOption("verbose"))
{
where <- function(x) if (verbose)
cat("Source: ", x, "\n", sep = "")
# loop through functions that lead here from most recent to earliest looking
# for an appropriate source call (a call to function base::source or base::sys.source)
# an appropriate source call is a source call in which
# argument 'file' has been evaluated (forced)
# this means, for example, the following is an inappropriate source call:
# source(this.path())
# the argument 'file' is stored as a promise
# containing the expression "this.path()"
# when the value of 'file' is requested, it assigns the value
# returned by evaluating "this.path()" to variable 'file'
# there are two functions on the calling stack at
# this point being 'source' and 'this.path'
# clearly, you don't want to request the 'file' argument from that source
# call because the value of 'file' is under evaluation right now!
# the trick is to ask if variable ('ofile' for base::source, 'exprs' for base::sys.source)
# exists in that function's evaluation environment. this is because that
# variable is created AFTER argument 'file' has been forced
# if that variable does exist, then argument 'file' has been forced and the
# source call is deemed appropriate. For base::source, the filename we want
# is the variable 'ofile' from that function's evaluation environment. For
# base::sys.source, the filename we want is the variable 'file' from that
# function's evaluation environment.
# if that variable does NOT exist, then argument 'file' hasn't been forced and
# the source call is deemed inappropriate. The 'for' loop moves to the next
# function up the calling stack (if available)
#
# unfortunately, there is no way to check the argument 'fileName' has been forced
# for 'debugSource' since all the work is done internally in C. Instead,
# we have to use a 'tryCatch' statement. When we ask for an object by name
# using 'get', R is capable of realizing if a variable is asking for its
# own definition (a recursive definition). The exact error is "promise already
# under evaluation" which indicates that the promise evaluation is requesting
# its own value. So we use the 'tryCatch' to get the argument 'fileName'
# from the evaluation environment of 'debugSource', and if it does not raise
# an error, then we are safe to return that value. If not, the condition
# returns false and the 'for' loop moves to the next function up the calling
# stack (if available)
if (.Platform$GUI == "RStudio")
dbs <- get("debugSource", mode = "function", "tools:rstudio",
inherits = FALSE)
for (n in seq.int(sys.nframe(), 1L)[-1L]) {
if (identical(sys.function(n), base::source) &&
exists("ofile", envir = sys.frame(n), inherits = FALSE)) {
path <- get("ofile", envir = sys.frame(n), inherits = FALSE)
if (!is.character(path))
path <- summary.connection(path)$description
where("call to function source")
return(normalizePath(path, mustWork = TRUE))
}
else if (identical(sys.function(n), base::sys.source) &&
exists("exprs", envir = sys.frame(n), inherits = FALSE)) {
path <- get("file", envir = sys.frame(n), inherits = FALSE)
where("call to function sys.source")
return(normalizePath(path, mustWork = TRUE))
}
else if (.Platform$GUI == "RStudio" && identical(sys.function(n), dbs) &&
tryCatch({
path <- get("fileName", envir = sys.frame(n), inherits = FALSE)
TRUE
}, error = function(c) {
FALSE
})) {
where("call to function debugSource in RStudio")
return(normalizePath(path, mustWork = TRUE))
}
}
# if the for loop is passed, no appropriate
# source call was found up the calling stack
# next, check if the user is running R from the command-line
# on a Windows OS, the GUI is "RTerm"
# on a Unix OS, the GUI is "X11"
if (.Platform$OS.type == "windows" && .Platform$GUI == "RTerm" || # running from Windows command-line
.Platform$OS.type == "unix" && .Platform$GUI == "X11") { # running from Unix command-line
# get all command-line arguments that start with "--file="
# check the number of command-line arguments starting with "--file="
# in case more or less than one were supplied
path <- grep("^--file=", commandArgs(), value = TRUE)
if (length(path) == 1L) {
path <- sub("^--file=", "", path)
where("Command-line argument 'file'")
return(normalizePath(path, mustWork = TRUE))
}
else if (length(path)) {
stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from the command-line and formal argument \"--file=\" matched by multiple actual arguments\n")
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from the command-line and argument \"--file=\" is missing\n")
}
else if (.Platform$GUI == "RStudio") { # running R from 'RStudio'
# function ".rs.api.getActiveDocumentContext" from the environment "tools:rstudio"
# returns a list of information about the document where your cursor is located
#
# function ".rs.api.getSourceEditorContext" from the environment "tools:rstudio"
# returns a list of information about the document open in the current tab
#
# element 'id' is a character string, an identification for the document
# element 'path' is a character string, the path of the document
adc <- get(".rs.api.getActiveDocumentContext",
mode = "function", "tools:rstudio", inherits = FALSE)()
if (adc$id != "#console") {
path <- adc$path
if (nzchar(path)) {
where("active document in RStudio")
return(normalizePath(path, mustWork = TRUE))
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* active document in RStudio does not exist\n")
}
sec <- get(".rs.api.getSourceEditorContext", mode = "function",
"tools:rstudio", inherits = FALSE)()
if (!is.null(sec)) {
path <- sec$path
if (nzchar(path)) {
where("source document in RStudio")
return(normalizePath(path, mustWork = TRUE))
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* source document in RStudio does not exist\n")
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from RStudio with no documents open\n")
}
else if (.Platform$OS.type == "windows" && .Platform$GUI == "Rgui") { # running R from 'RGui' on Windows
# on a Windows OS only, the function "getWindowsHandles" from the base
# package "utils" returns a list of external pointers containing the windows
# handles. The thing of interest are the names of this list, these should
# be the names of the windows belonging to the current R process. Since
# RGui can have files besides R scripts open (such as images), a regular
# expression is used to subset only windows handles with names that exactly
# match the string "R Console" or end with " - R Editor". I highly suggest
# that you NEVER end a document's filename with " - R Editor". From there,
# similar checks are done as in the above section for 'RStudio'
wh <- names(utils::getWindowsHandles(pattern = "^R Console$| - R Editor$",
minimized = TRUE))
if (!length(wh))
stop("this error SHOULD be unreachable, as far as I know it's impossible to have an R\n",
" process running without the R Console open. If you reached this error, please\n",
" send a bug report to the package maintainer")
path <- wh[1L]
if (path != "R Console") {
path <- sub(" - R Editor$", "", path)
if (path != "Untitled") {
where("active document in RGui")
return(normalizePath(path, mustWork = TRUE))
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* active document in RGui does not exist\n")
}
path <- wh[2L]
if (!is.na(path)) {
path <- sub(" - R Editor$", "", path)
if (path != "Untitled") {
where("source document in RGui")
return(normalizePath(path, mustWork = TRUE))
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* source document in RGui does not exist\n")
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from RGui with no documents open\n")
}
else if (.Platform$OS.type == "unix" && .Platform$GUI == "AQUA") { # running R from 'RGui' on Unix
stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from AQUA which requires a source call on the calling stack\n")
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run in an unrecognized manner\n")
}
Мои все в одном!
#' current script file (in full path)
#' @param
#' @return
#' @examples
#' works with Rscript, source() or in RStudio Run selection
#' @export
csf <- function() {
# http://stackru.com/a/32016824/2292993
cmdArgs = commandArgs(trailingOnly = FALSE)
needle = "--file="
match = grep(needle, cmdArgs)
if (length(match) > 0) {
# Rscript via command line
return(normalizePath(sub(needle, "", cmdArgs[match])))
} else {
ls_vars = ls(sys.frames()[[1]])
if ("fileName" %in% ls_vars) {
# Source'd via RStudio
return(normalizePath(sys.frames()[[1]]$fileName))
} else {
if (!is.null(sys.frames()[[1]]$ofile)) {
# Source'd via R console
return(normalizePath(sys.frames()[[1]]$ofile))
} else {
# RStudio Run Selection
# http://stackru.com/a/35842176/2292993
return(normalizePath(rstudioapi::getActiveDocumentContext()$path))
}
}
}
}
Уменьшенный вариант ответа Supressingfire:
source_local <- function(fname){
argv <- commandArgs(trailingOnly = FALSE)
base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
source(paste(base_dir, fname, sep="/"))
}
Это работает для меня. Просто извлекает его из аргументов командной строки, удаляет нежелательный текст, делает имя и, наконец, получает полный путь от этого:
args <- commandArgs(trailingOnly = F)
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))
Я обернул и расширил ответы на этот вопрос в новую функцию thisfile()
в rprojroot. Также работает для вязания с knitr
,
Я попробовал почти все из этого вопроса: " Получить путь к R-сценарию", " Получить путь к текущему сценарию", " Найти местоположение текущего.R-файла" и " Команда R" для установки рабочего каталога на местоположение исходного файла в Rstudio, но в конце я оказался вручную просматривая таблицу CRAN и находя
scriptName
библиотека
который обеспечивает current_filename()
функция, которая возвращает правильный полный путь скрипта при поиске в RStudio, а также при вызове через исполняемый файл R или RScript.
Мне понравилось решение steamer25, так как оно кажется наиболее надежным для моих целей. Однако при отладке в RStudio (в windows) путь не будет установлен правильно. Причина в том, что если в RStudio установлена точка останова, то для поиска файла используется альтернативная команда "источник отладки", которая задает путь к сценарию немного по-другому. Вот последняя версия, которую я сейчас использую, которая объясняет это альтернативное поведение в RStudio при отладке:
# @return full path to this script
get_script_path <- function() {
cmdArgs = commandArgs(trailingOnly = FALSE)
needle = "--file="
match = grep(needle, cmdArgs)
if (length(match) > 0) {
# Rscript
return(normalizePath(sub(needle, "", cmdArgs[match])))
} else {
ls_vars = ls(sys.frames()[[1]])
if ("fileName" %in% ls_vars) {
# Source'd via RStudio
return(normalizePath(sys.frames()[[1]]$fileName))
} else {
# Source'd via R console
return(normalizePath(sys.frames()[[1]]$ofile))
}
}
}
Я сам все решил. Чтобы обеспечить переносимость вашего скрипта, всегда начинайте его с:
wd <- setwd(".")
setwd(wd)
Это работает, потому что "." переводится как команда Unix $PWD. Присвоение этой строки символьному объекту позволяет затем вставить этот символьный объект в setwd(), и Presto ваш код всегда будет работать с его текущим каталогом в качестве рабочего каталога, независимо от того, на каком компьютере он находится или где в файловой структуре он находится. расположен. (Дополнительный бонус: объект wd можно использовать с file.path() (т. Е. File.path(wd, "output_directory"), чтобы создать стандартный выходной каталог независимо от пути к файлу, ведущему к названному каталогу. Это требует от вас создания нового каталога перед тем, как ссылаться на него таким образом, но этому тоже можно помочь с объектом wd.
Альтернативно, следующий код выполняет ту же функцию:
wd <- getwd()
setwd(wd)
или, если вам не нужен путь к файлу в объекте, вы можете просто:
setwd(".")
У меня тоже была эта проблема, и ни одно из вышеперечисленных решений не помогло мне. Может быть, сsource
или тому подобное, но это было недостаточно ясно.
Я нашел это, на мой взгляд, элегантное решение:
paste0(gsub("\\", "/", fileSnapshot()$path, fixed=TRUE),"/")
Главное в этом fileSnapshot()
это дает вам много информации о файле. Он возвращает список из 8 элементов. Когда вы выбираетеpath
в качестве элемента списка путь возвращается с \\
в качестве разделителя, поэтому остальная часть кода предназначена только для его изменения.
Надеюсь, это поможет.
Если вместо сценария, foo.R
, зная его путь, если вы можете изменить свой код, чтобы всегда ссылаться на все source
извлекал из общего root
тогда это может быть большой помощью:
Дано
/app/deeply/nested/foo.R
/app/other.R
Это будет работать
#!/usr/bin/env Rscript
library(here)
source(here("other.R"))
См. https://krlmlr.github.io/rprojroot/ чтобы узнать, как определить корни проекта.
Подход Steamer25 работает, но только если на пути нет пробелов. На macOS хотя бы cmdArgs[match]
возвращает что-то вроде /base/some~+~dir~+~with~+~whitespace/
за /base/some\ dir\ with\ whitespace/
,
Я обошел это, заменив "~+~" простым пробелом перед его возвратом.
thisFile <- function() {
cmdArgs <- commandArgs(trailingOnly = FALSE)
needle <- "--file="
match <- grep(needle, cmdArgs)
if (length(match) > 0) {
# Rscript
path <- cmdArgs[match]
path <- gsub("\\~\\+\\~", " ", path)
return(normalizePath(sub(needle, "", path)))
} else {
# 'source'd via R console
return(normalizePath(sys.frames()[[1]]$ofile))
}
}
Очевидно, вы можете расширить блок else, как это сделал aprstar.
Вы можете обернуть скрипт r в скрипт bash и получить путь к скрипту как переменную bash следующим образом:
#!/bin/bash
# [environment variables can be set here]
path_to_script=$(dirname $0)
R --slave<<EOF
source("$path_to_script/other.R")
EOF
Обратите внимание, что пакет getopt предоставляет get_Rscript_filename
функция, которая просто использует то же решение, что и здесь, но уже написана для вас в стандартном модуле R, поэтому вам не нужно копировать и вставлять функцию "get script path" в каждый скрипт, который вы пишете.
Мне нравится этот подход:
this.file <- sys.frame(tail(grep('source',sys.calls()),n=1))$ofile
this.dir <- dirname(this.file)
Я бы использовал вариант подхода @steamer25. Дело в том, что я предпочитаю получать последний исходный скрипт, даже когда мой сеанс был запущен через Rscript. Следующий фрагмент, если он включен в файл, предоставит переменную thisScript
содержащий нормализованный путь скрипта. Я признаю (ab) использование source'ing, поэтому иногда я вызываю Rscript и скрипт, предоставленный в --file
Аргумент источник другой сценарий, который источник другой... Когда-нибудь я буду инвестировать в превращение моего грязного кода в пакет.
thisScript <- (function() {
lastScriptSourced <- tail(unlist(lapply(sys.frames(), function(env) env$ofile)), 1)
if (is.null(lastScriptSourced)) {
# No script sourced, checking invocation through Rscript
cmdArgs <- commandArgs(trailingOnly = FALSE)
needle <- "--file="
match <- grep(needle, cmdArgs)
if (length(match) > 0) {
return(normalizePath(sub(needle, "", cmdArgs[match]), winslash=.Platform$file.sep, mustWork=TRUE))
}
} else {
# 'source'd via R console
return(normalizePath(lastScriptSourced, winslash=.Platform$file.sep, mustWork=TRUE))
}
})()
Наиболее гибкое решение этой проблемы, которое я нашел, используетrstudioapi::getSourceEditorContext()
и (необязательно)sub()
- Работайте в интерактивном режиме со сценариями .Rmd и .R.
- Работает при вязании файла .Rmd.
- Работает при поиске файла .R.
Попробуйте следующее:
current_file <-
rstudioapi::getSourceEditorContext()$path %>%
sub(".*/", "", .)
The rstudioapi::getSourceEditorContext()$path
возвращает полный путь к текущему файлу
The sub(".*/", "", .)
извлекает все после последнего/
, оставив только имя файла.
Надеюсь, это поможет!
В 99% случаев вы можете просто использовать:
sys.calls()[[1]] [[2]]
Это не будет работать для сумасшедших вызовов, где сценарий не является первым аргументом, т.е. source(some args, file="myscript")
, Используйте @hadley's в этих необычных случаях.
Решение пришло в 2016 году. Большое спасибо автору Сахилу Сету!
Посылка
funr
на CRAN и github предоставляет функцию
sys.script()
который получает полный путь к текущему скрипту. Он даже ссылается на аналогичный пост SO .
Таким образом, решение:
myscript.R:
#!/usr/bin/env Rscript
f <- funr::sys.script()
show(f)
а затем выполните команду:
user@somewhere:/home$ Rscript myscript.R
в командной строке будет выводиться, например:
"/home/path/to/myscript.R"
к консоли.
Посмотрев на стек вызовов, мы можем получить путь к файлу для каждого выполняемого сценария, два наиболее полезных из которых, вероятно, будут либо выполняемым в данный момент сценарием, либо первым источником сценария (вход).
script.dir.executing = (function() return( if(length(sys.parents())==1) getwd() else dirname( Filter(is.character,lapply(rev(sys.frames()),function(x) x$ofile))[[1]] ) ))()
script.dir.entry = (function() return( if(length(sys.parents())==1) getwd() else dirname(sys.frame(1)$ofile) ))()
Увидеть findSourceTraceback()
пакета R.utils, который
Находит все объекты 'srcfile', сгенерированные source() во всех фреймах вызова. Это позволяет выяснить, какие файлы в настоящее время записываются в сценарии source().
У меня были проблемы с реализациями, описанными выше, так как мой скрипт работает из каталога с символическими ссылками, или, по крайней мере, поэтому я думаю, что вышеупомянутые решения не сработали для меня. В соответствии с ответом @ ennuikiller, я завернул свой Rscript в bash. Я устанавливаю переменную пути, используя pwd -P
, который разрешает символьные структуры каталогов. Затем пройдите путь в Rscript.
Bash.sh
#!/bin/bash
# set path variable
path=`pwd -P`
#Run Rscript with path argument
Rscript foo.R $path
foo.R
args <- commandArgs(trailingOnly=TRUE)
setwd(args[1])
source(other.R)
Я работаю в кластерной среде HPC. Я разрабатываю свой код не в том месте, где я занимаюсь производством. Во время разработки я обычно вызываю R в интерактивном режиме из командной строки (не используя RStudio). Есть многоsource("foo.R")
продолжается.
Во время производственного запуска я обычно пишу сценарий bash, который пробует разные параметры и запускает каждый набор параметров в отдельном каталоге. Сценарий bash использует диспетчер рабочей нагрузки (например, SLURM). В этой среде установить переменную среды очень просто. Имея это в виду, для меня лучше всего подходит приведенное ниже решение.
другой.R
my_message <- function(){
return("R is awkward")
}
foo.R
srcpath = Sys.getenv("R_SRC")
# Check if runnning w/o setting R_SRC - presumably done in directory of development, i.e. /path/to/R/code
if(srcpath == ""){
srcpath="./"
}
source(sprintf("%s/other.R", srcpath))
string = my_message()
print(string)
Если запустить это из интерактивной оболочки R и внутри /path/to/R/code
просто сделай
> source("foo.R")
Если запускается не из интерактивной оболочки и не из /path/to/R/code
, установите переменную среды R_SRC
сначала позвони Rscript
$ export R_SRC=/path/to/R/code/
$ Rscript /path/to/R/code/foo.R
#!/usr/bin/env Rscript
print("Hello")
# sad workaround but works :(
programDir <- dirname(sys.frame(1)$ofile)
source(paste(programDir,"other.R",sep='/'))
source(paste(programDir,"other-than-other.R",sep='/'))
Чтобы опираться на приведенные выше ответы, в качестве проверки безопасности вы можете добавить оболочку, которая просит пользователя найти файл, если (по какой-либо причине)
sys.frame(1)
терпит неудачу (как это могло бы быть, если бы
interactive() == TRUE
), или исходный сценарий находится не там, где его ожидает основной сценарий.
fun_path = tryCatch(expr =
{file.path(dirname(sys.frame(1)$ofile), "foo.R")},
error = function(e){'foo.R'}
)
if(!file.exists(fun_path))
{
msg = 'Please select "foo.R"'
# ask user to find data
if(Sys.info()[['sysname']] == 'Windows'){#choose.files is only available on Windows
message('\n\n',msg,'\n\n')
Sys.sleep(0.5)#goes too fast for the user to see the message on some computers
fun_path = choose.files(
default = file.path(gsub('\\\\', '/', Sys.getenv('USERPROFILE')),#user
'Documents'),
caption = msg
)
}else{
message('\n\n',msg,'\n\n')
Sys.sleep(0.5)#goes too fast for the user to see the message on some computers
fun_path = file.choose(new=F)
}
}
#source the function
source(file = fun_path,
encoding = 'UTF-8')