file Rscript: определение пути исполняемого скрипта



12 Answers

Вы можете использовать функцию commandArgs чтобы получить все параметры, которые были переданы Rscript, фактическому интерпретатору R и искать их для --file= . Если ваш скрипт был запущен с пути или был запущен с полным путем, имя script.name ниже начинается с script.name '/' . В противном случае это должно быть относительно cwd и вы можете выполнить два пути, чтобы получить полный путь.

Редактировать: похоже, вам понадобится только script.name выше и удалить последний компонент пути. Я удалил ненужный cwd() образец и очистил основной скрипт и опубликовал мой other.R . Просто сохраните этот скрипт и скрипт other.R в том же каталоге, chmod +x them и запустите основной скрипт.

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"

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

r file path rscript r-faq

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

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

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

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




frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])

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




Вырезанный вариант ответа Supressingfire:

source_local <- function(fname){
    argv <- commandArgs(trailingOnly = FALSE)
    base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
    source(paste(base_dir, fname, sep="/"))
}



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

args <- commandArgs(trailingOnly = F)  
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))



Мне понравилось решение steamer25, поскольку оно кажется самым надежным для моих целей. Однако при отладке в RStudio (в окнах) путь не будет установлен правильно. Причина заключается в том, что если в 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))
        }
    }
}



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




Мне нравится такой подход:

this.file <- sys.frame(tail(grep('source',sys.calls()),n=1))$ofile
this.dir <- dirname(this.file)



См. findSourceTraceback() пакета R.utils , который

Находит все объекты srcfile, сгенерированные источником () во всех кадрах вызовов. Это позволяет узнать, какие файлы в настоящее время написаны с помощью source ().




Я бы использовал вариант подхода @ 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))
  }
})()



Я попробовал почти все из этого вопроса: « Путь к сценарию R» , « Получить путь к текущему сценарию» , « Найти местоположение текущего файла .R и команды R для установки рабочего каталога в исходное расположение файла в Rstudio , но в конце нашел себя вручную просматривая таблицу CRAN и обнаружив

библиотека scriptName

который предоставляет функцию current_filename() , которая возвращает правильный полный путь к скрипту при поиске в RStudio, а также при вызове через R или исполняемый файл RScript.




Подход Steamer25 работает, но только если в пути нет пробелов. На macOS по крайней мере cmdArgs[match] возвращает что-то вроде /base/some~+~dir~+~with~+~whitespace/ for /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 нет структуры типа «$ 0»! Вы можете сделать это с помощью вызова system () для сценария bash, написанного в R:

write.table(c("readlink -e $0"), file="scriptpath.sh",col=F, row=F, quote=F)
thisscript <- system("sh scriptpath.sh", intern = TRUE)

Затем просто разделите имя scriptpath.sh для other.R

splitstr <- rev(strsplit(thisscript, "\\/")[[1]])
otherscript <- paste0(paste(rev(splitstr[2:length(splitstr)]),collapse="/"),"/other.R")



Related