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')
Другие вопросы по тегам