Получение пути R-скрипта
Есть ли способ программно найти путь к сценарию R внутри самого сценария?
Я спрашиваю об этом, потому что у меня есть несколько сценариев, которые используют RGtk2
и загрузите графический интерфейс из файла.glade.
В этих сценариях я обязан поставить setwd("path/to/the/script")
инструкция в начале, иначе файл.glade (который находится в том же каталоге) не будет найден.
Это нормально, но если я перенесу сценарий в другой каталог или на другой компьютер, мне придется изменить путь. Я знаю, это не имеет большого значения, но было бы неплохо иметь что-то вроде:
setwd(getScriptPath())
Итак, существует ли подобная функция?
14 ответов
Это работает для меня:
getSrcDirectory(function(x) {x})
Это определяет анонимную функцию (которая ничего не делает) внутри скрипта, а затем определяет исходный каталог этой функции, который является каталогом, в котором находится скрипт.
Только для RStudio:
setwd(dirname(rstudioapi::getActiveDocumentContext()$path))
Это работает при запуске ning или Sourceing вашего файла.
Используйте неявный аргумент "--file" в Rscript
При вызове сценария с использованием "Rscript" ( Rscript doc) полный путь к сценарию указывается в качестве системного параметра. Следующая функция использует это для извлечения каталога скриптов:
getScriptPath <- function(){
cmd.args <- commandArgs()
m <- regexpr("(?<=^--file=).+", cmd.args, perl=TRUE)
script.dir <- dirname(regmatches(cmd.args, m))
if(length(script.dir) == 0) stop("can't determine script dir: please call the script with Rscript")
if(length(script.dir) > 1) stop("can't determine script dir: more than one '--file' argument detected")
return(script.dir)
}
Если вы упаковываете свой код в пакет, вы всегда можете запросить части каталога пакета.
Вот пример из пакета RGtk2:
> system.file("ui", "demo.ui", package="RGtk2")
[1] "C:/opt/R/library/RGtk2/ui/demo.ui"
>
Вы можете сделать то же самое с каталогом inst/glade/
в ваших источниках, которые станут каталогом glade/
в установленном пакете - и system.file()
вычислит путь для вас после установки, независимо от ОС.
Этот ответ хорошо работает для меня:
script.dir <- dirname(sys.frame(1)$ofile)
Примечание: сценарий должен быть получен, чтобы вернуть правильный путь
Я нашел это в: https://support.rstudio.com/hc/communities/public/questions/200895567-can-user-obtain-the-path-of-current-Project-s-directory-
Но я все еще не понимаю, что такое sys.frame(1)$ofile. Я не нашел ничего об этом в документации R. Кто-то может это объяснить?
#' current script dir
#' @param
#' @return
#' @examples
#' works with source() or in RStudio Run selection
#' @export
z.csd <- function() {
# http://stackru.com/questions/1815606/rscript-determine-path-of-the-executing-script
# must work with source()
if (!is.null(res <- .thisfile_source())) res
else if (!is.null(res <- .thisfile_rscript())) dirname(res)
# http://stackru.com/a/35842176/2292993
# RStudio only, can work without source()
else dirname(rstudioapi::getActiveDocumentContext()$path)
}
# Helper functions
.thisfile_source <- function() {
for (i in -(1:sys.nframe())) {
if (identical(sys.function(i), base::source))
return (normalizePath(sys.frame(i)$ofile))
}
NULL
}
.thisfile_rscript <- function() {
cmdArgs <- commandArgs(trailingOnly = FALSE)
cmdArgsTrailing <- commandArgs(trailingOnly = TRUE)
cmdArgs <- cmdArgs[seq.int(from=1, length.out=length(cmdArgs) - length(cmdArgsTrailing))]
res <- gsub("^(?:--file=(.*)|.*)$", "\\1", cmdArgs)
# If multiple --file arguments are given, R uses the last one
res <- tail(res[res != ""], 1)
if (length(res) > 0)
return (res)
NULL
}
Я нашел то, что работает для меня.
setwd(dirname(rstudioapi::getActiveDocumentContext()$path))
Многим из этих решений уже несколько лет. Хотя некоторые из них могут работать, есть веские причины не использовать каждый из них (см. Связанный источник ниже). У меня есть лучшее решение (тоже из источника): используйтеhere
библиотека.
Исходный пример кода:
library(ggplot2)
setwd("/Users/jenny/cuddly_broccoli/verbose_funicular/foofy/data")
df <- read.delim("raw_foofy_data.csv")
Исправленный код
library(ggplot2)
library(here)
df <- read.delim(here("data", "raw_foofy_data.csv"))
Это решение является наиболее динамичным и надежным, потому что оно работает независимо от того, используете ли вы командную строку, RStudio, вызываете ли вы из сценария R и т. Д. Оно также чрезвычайно просто в использовании и является лаконичным.
Источник: https://www.tidyverse.org/articles/2017/12/workflow-vs-script/
В моем случае мне нужен был способ скопировать исполняемый файл для резервного копирования исходного скрипта вместе с его выходными данными. Это относительно важно в исследованиях. Что сработало для меня при запуске моего скрипта в командной строке, так это смесь других представленных здесь решений, которые выглядят так:
library(scriptName)
file_dir <- paste0(gsub("\\", "/", fileSnapshot()$path, fixed=TRUE))
file.copy(from = file.path(file_dir, scriptName::current_filename()) ,
to = file.path(new_dir, scriptName::current_filename()))
В качестве альтернативы, можно добавить к имени файла дату и наш, чтобы помочь отличить этот файл от источника следующим образом:
file.copy(from = file.path(current_dir, current_filename()) ,
to = file.path(new_dir, subDir, paste0(current_filename(),"_", Sys.time(), ".R")))
Я знаю, что этот вопрос устарел на данный момент, но я хотел бы ответить, потому что я сделал пакет для решения этой проблемы. Он называется «this.path» и доступен в CRAN, поэтому его можно установить, как и любой другой пакет, используя: install.packages («this.path»)
Он должен получить имя файла исполняемого скрипта при запуске R из RStudio, RGui, командной строки / / терминала (Rscript) и при использовании «источника».
Ни одно из решений, представленных до сих пор, не работает во всех обстоятельствах. Хуже того, многие решения используют , и, таким образом, ломают код, который ожидает, что рабочий каталог будет рабочим каталогом , то есть кодом, который выбрал пользователь кода (я понимаю, что вопрос касается
setwd()
но это не меняет того факта, что это вообще плохая идея).
R просто не имеет встроенного способа определить путь к текущему фрагменту кода.
Чистое решение требует систематического способа управления непакетным кодом. Это то, что делает «коробка» . С помощью «box» каталог, относящийся к текущему выполняемому коду, можно найти тривиально:
box::file()
Однако цель «коробки» не в этом; это просто побочный эффект того, что он на самом деле делает: он реализует правильную современную модульную систему для R. Это включает в себя организацию кода в (вложенных) модулях и, следовательно, возможность загружать код из модулей относительно текущего кода.
Чтобы загрузить код с «коробкой», вы бы не использовали, например
source(file.path(box::file(), 'foo.r'))
. Вместо этого вы должны использовать
box::use(./foo)
Однако,
box::file()
по-прежнему полезен для поиска данных (например, вариант использования OP). Так, например, чтобы найти файл
mygui.glade
из текущего пути модуля, вы бы написали.
glade_path = box::file('mygui.glade')
И (пока вы используете «коробочные» модули) это всегда работает, не требует никаких хаков и не использует
setwd
.
Спасибо за функцию, хотя мне пришлось немного ее настроить, как показано ниже (W10):
#Windows Command Prompt Commands
if(win==1){
file_path<-shell('dir file_name', intern = TRUE)
file_path<-file_path[4]
file_path<-gsub(" Verzeichnis von ","",file_path)
file_path<-chartr("\\","/",file_path)
data_directory<-file_path
}
Как насчет использования системных команд и команд оболочки? С Windows One, я думаю, что когда вы открываете скрипт в RStudio, он устанавливает текущий каталог оболочки в каталог скрипта. Возможно, вам придется добавить cd C:\ например или любой диск, который вы хотите найти (например, shell('dir C:\\* имя_файла /s', intern = TRUE) - \\ для экранирования escape-символа). Будет работать только для файлов с уникальными именами, если вы не укажете дополнительные подкаталоги (для Linux я начал поиск с /). В любом случае, если вы знаете, как найти что-то в оболочке, это обеспечивает компоновку, чтобы найти это в R и вернуть каталог. Должно работать, независимо от того, используете ли вы скрипт или запускаете скрипт, но я не полностью изучил потенциальные ошибки.
#Get operating system
OS<-Sys.info()
win<-length(grep("Windows",OS))
lin<-length(grep("Linux",OS))
#Find path of data directory
#Linux Bash Commands
if(lin==1){
file_path<-system("find / -name 'file_name'", intern = TRUE)
data_directory<-gsub('/file_name',"",file_path)
}
#Windows Command Prompt Commands
if(win==1){
file_path<-shell('dir file_name /s', intern = TRUE)
file_path<-file_path[4]
file_path<-gsub(" Directory of ","",file_path)
filepath<-gsub("\\\\","/",file_path)
data_directory<-file_path
}
#Change working directory to location of data and sources
setwd(data_directory)