Определить путь к исполняемому скрипту - PullRequest
220 голосов
/ 29 ноября 2009

У меня есть скрипт с именем foo.R, который включает другой скрипт other.R, который находится в том же каталоге:

#!/usr/bin/env Rscript
message("Hello")
source("other.R")

Но я хочу, чтобы R нашел это other.R независимо от текущего рабочего каталога.

Другими словами, foo.R должен знать свой собственный путь. Как я могу это сделать?

Ответы [ 24 ]

87 голосов
/ 17 апреля 2013

Здесь есть простое решение проблемы. Эта команда:

script.dir <- dirname(sys.frame(1)$ofile)

возвращает путь к текущему файлу скрипта. Работает после сохранения скрипта.

63 голосов
/ 29 ноября 2009

Вы можете использовать функцию 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)

other.R

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"

Это то, что я считаю, что Дехманн ищет.

50 голосов
/ 13 марта 2013

Мне не удалось заставить работать решение 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))
        }
}
35 голосов
/ 29 ноября 2009
frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])

Не спрашивайте меня, как это работает, потому что я забыл: /

22 голосов
/ 29 марта 2016

Ответ rakensi из Получение пути к R-скрипту является наиболее правильным и действительно блестящим ИМХО Тем не менее, это все еще хак, включающий фиктивную функцию. Я цитирую это здесь, чтобы другим было легче его найти.

sourceDir <- getSrcDirectory (function (dummy) {dummy}) </p>

Это дает каталог файла, где был помещен оператор (где определена фиктивная функция). Затем его можно использовать для установки рабочего каталога и использования относительных путей, например

setwd(sourceDir)
source("other.R")

или для создания абсолютных путей

 source(paste(sourceDir, "/other.R", sep=""))
21 голосов
/ 23 августа 2017

Это работает для меня

library(rstudioapi)    
rstudioapi::getActiveDocumentContext()$path
12 голосов
/ 24 июня 2011

уменьшенный вариант ответа Supressingfire:

source_local <- function(fname){
    argv <- commandArgs(trailingOnly = FALSE)
    base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
    source(paste(base_dir, fname, sep="/"))
}
11 голосов
/ 21 апреля 2016

Мои все в одном! (- 01/01/2019 обновлено для работы с RStudio Console)

#' current script file (in full path)
#' @description current script file (in full path)
#' @examples
#' works with Rscript, source() or in RStudio Run selection, RStudio Console
#' @export
ez.csf <- function() {
    # http://stackoverflow.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://stackoverflow.com/a/35842176/2292993
                pth = rstudioapi::getActiveDocumentContext()$path
                if (pth!='') {
                    return(normalizePath(pth))
                } else {
                    # RStudio Console
                    tryCatch({
                            pth = rstudioapi::getSourceEditorContext()$path
                            pth = normalizePath(pth)
                        }, error = function(e) {
                            # normalizePath('') issues warning/error
                            pth = ''
                        }
                    )
                    return(pth)
                }
            }
        }
    }
}
10 голосов
/ 28 сентября 2011

Это работает для меня. Просто извлекает его из аргументов командной строки, удаляет ненужный текст, делает имя и, наконец, получает полный путь от этого:

args <- commandArgs(trailingOnly = F)  
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))
6 голосов
/ 29 ноября 2013

Я завернул и расширил ответы на этот вопрос в новую функцию thisfile() в rprojroot . Также работает для вязания с knitr.

...