current - r get file dir
Rscript: Determine la ruta del script en ejecuciĆ³n (24)
Tengo un script llamado foo.R
que incluye otro script other.R
, que está en el mismo directorio:
#!/usr/bin/env Rscript
print("Hello")
source("other.R")
Pero quiero que R
encuentre ese other.R
No importa cuál sea el directorio de trabajo actual.
En otras palabras, foo.R
necesita conocer su propio camino. ¿Cómo puedo hacer eso?
¡Increíble, no hay una estructura de tipo ''$ 0'' en R! Puede hacerlo con una llamada a system () a un script bash escrito en R:
write.table(c("readlink -e $0"), file="scriptpath.sh",col=F, row=F, quote=F)
thisscript <- system("sh scriptpath.sh", intern = TRUE)
Luego simplemente divide el nombre de scriptpath.sh para otro.R
splitstr <- rev(strsplit(thisscript, "///")[[1]])
otherscript <- paste0(paste(rev(splitstr[2:length(splitstr)]),collapse="/"),"/other.R")
Acabo de resolver esto yo mismo. Para asegurar la portabilidad de su script comience siempre con:
wd <- setwd(".")
setwd(wd)
Funciona porque "." se traduce como el comando de Unix $ PWD. Asignar esta cadena a un objeto de carácter le permite insertar ese objeto de carácter en setwd () y Presto su código siempre se ejecutará con su directorio actual como el directorio de trabajo, sin importar en qué máquina se encuentre o en qué parte de la estructura de archivos se encuentre. situado. (Extra extra: el objeto wd se puede usar con file.path () (es decir, file.path (wd, "output_directory") para permitir la creación de un directorio de salida estándar, independientemente de la ruta del archivo que lleva a su directorio nombrado. Esto requiere que haga el nuevo directorio antes de referenciarlo de esta manera, pero eso también puede ayudarse con el objeto wd.
Alternativamente, el siguiente código realiza exactamente lo mismo:
wd <- getwd()
setwd(wd)
o, si no necesita la ruta del archivo en un objeto, simplemente puede:
setwd(".")
Consulte findSourceTraceback()
del paquete R.utils , que
Encuentra todos los objetos ''srcfile'' generados por source () en todos los marcos de llamadas. Esto hace que sea posible averiguar qué archivos están actualmente en secuencias de comandos mediante source ().
El 99% de los casos que podría utilizar simplemente:
sys.calls()[[1]] [[2]]
No funcionará para llamadas locas donde la secuencia de comandos no es el primer argumento, es decir, la source(some args, file="myscript")
argumentos source(some args, file="myscript")
. Usa @ hadley en estos casos elegantes.
El enfoque de Steamer25 funciona, pero solo si no hay espacios en blanco en la ruta. En macOS, al menos el cmdArgs[match]
devuelve algo como /base/some~+~dir~+~with~+~whitespace/
for /base/some/ dir/ with/ whitespace/
.
Resolví esto al reemplazar el "~ + ~" con un espacio en blanco simple antes de devolverlo.
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))
}
}
Obviamente todavía puedes extender el bloque else como lo hizo aprstar.
Envolví y extendí las respuestas a esta pregunta en una nueva función thisfile()
en rprojroot . También funciona para tejer con knitr
.
Esto funciona para mi Simplemente saca los argumentos de la línea de comandos, elimina el texto no deseado, hace un dirname y finalmente obtiene la ruta completa de eso:
args <- commandArgs(trailingOnly = F)
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))
Esto funciona para mi
library(rstudioapi)
rstudioapi::getActiveDocumentContext()$path
Intenté casi todo desde esta pregunta, Obtención de la ruta de acceso de una secuencia de comandos R , Obtención de la ruta de la secuencia de comandos actual , Buscar ubicación del archivo .R actual y Comando R para configurar el directorio de trabajo en la ubicación del archivo fuente en Rstudio , pero al final me encontré manualmente navegando por la tabla CRAN y encontrada
biblioteca scriptName
que proporciona current_filename()
función, que devuelve la ruta completa correcta de la secuencia de comandos al obtener recursos en RStudio y también cuando se invoca a través de R o ejecutable RScript.
La respuesta de rakensi de Getting path of a R script es la IMHO más correcta y realmente brillante. Sin embargo, sigue siendo un truco que incorpora una función ficticia. Lo cito aquí, para que otros puedan encontrarlo más fácilmente.
sourceDir <- getSrcDirectory (function (dummy) {dummy})
Esto proporciona el directorio del archivo donde se colocó la declaración (donde se define la función ficticia). Luego puede usarse para configurar el directorio de trabajo y usar rutas relativas, por ejemplo,
setwd(sourceDir)
source("other.R")
o para crear caminos absolutos
source(paste(sourceDir, "/other.R", sep=""))
Me gustó la solución de steamer25 ya que parece la más robusta para mis propósitos. Sin embargo, al depurar en RStudio (en Windows), la ruta no se establecería correctamente. La razón es que si se establece un punto de interrupción en RStudio, la fuente del archivo utiliza un comando alternativo "fuente de depuración" que establece la ruta del script de forma un poco diferente. Aquí está la versión final que estoy usando actualmente, lo que explica este comportamiento alternativo dentro de RStudio al depurar:
# @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))
}
}
}
Me gusta este enfoque:
this.file <- sys.frame(tail(grep(''source'',sys.calls()),n=1))$ofile
this.dir <- dirname(this.file)
Mi todo en uno!
#'' current script file (in full path)
#'' @param
#'' @return
#'' @examples
#'' works with Rscript, source() or in RStudio Run selection
#'' @export
csf <- function() {
# http://.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://.com/a/35842176/2292993
return(normalizePath(rstudioapi::getActiveDocumentContext()$path))
}
}
}
}
No pude conseguir que la solución de Suppressingfire funcionara cuando se ''originara'' desde la consola R.
No pude conseguir que la solución de hadley funcionara al usar Rscript.
¿Lo mejor de ambos mundos?
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))
}
}
Puede envolver el script r en un script bash y recuperar la ruta del script como una variable bash así:
#!/bin/bash
# [environment variables can be set here]
path_to_script=$(dirname $0)
R --slave<<EOF
source("$path_to_script/other.R")
EOF
Puede usar la función commandArgs
para obtener todas las opciones que Rscript pasó al intérprete de R real y buscarlas --file=
. Si su script se inició desde la ruta o si se inició con una ruta completa, el script.name
continuación comenzará con ''/''
. De lo contrario, debe ser relativo al cwd
y puede concat las dos rutas para obtener la ruta completa.
Edición: suena como si solo necesitaras el script.name
arriba y eliminar el componente final de la ruta. cwd()
muestra de cwd()
innecesaria, cwd()
el script principal y other.R
mi other.R
. Simplemente guarde este script y el other.R
script de other.R
en el mismo directorio, chmod +x
ellos, y ejecute el script principal.
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)
otro.R :
print("hello")
salida :
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"
Esto es lo que creo que está buscando Dehmann.
Si en lugar de la secuencia de comandos, foo.R
, conociendo su ubicación de ruta, si puede cambiar su código para que siempre haga referencia a todas las rutas de origen desde una root
común, esto puede ser de gran ayuda:
Dado
-
/app/deeply/nested/foo.R
-
/app/other.R
Esto funcionara
#!/usr/bin/env Rscript
library(here)
source(here("other.R"))
Vea https://krlmlr.github.io/rprojroot/ para https://krlmlr.github.io/rprojroot/ cómo definir las raíces del proyecto.
Tenga en cuenta que el paquete getopt proporciona la función get_Rscript_filename
, que solo usa la misma solución presentada aquí, pero que ya está escrita para usted en un módulo R estándar, por lo que no tiene que copiar y pegar la función "obtener la ruta del script" en cada guión que escribes
Tuve problemas con las implementaciones anteriores ya que mi script es operado desde un directorio con enlaces simbólicos, o al menos por eso creo que las soluciones anteriores no funcionaron para mí. En la línea de la respuesta de @ennuikiller, envolví mi Rscript en bash. Establecí la variable de ruta usando pwd -P
, que resuelve las estructuras de directorios vinculados por enlaces. Luego pasa el camino en el 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)
Una variante reducida de la respuesta de Supressingfire:
source_local <- function(fname){
argv <- commandArgs(trailingOnly = FALSE)
base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
source(paste(base_dir, fname, sep="/"))
}
Yo usaría una variante del enfoque de @ steamer25. El punto es que prefiero obtener el último script de origen incluso cuando mi sesión se inició a través de Rscript. El siguiente fragmento de código, cuando se incluye en un archivo, proporcionará una variable que contiene la ruta normalizada del script. Confieso el uso (ab) de source''ing, por lo que a veces invoco Rscript y el script provisto en el --file
argumento --file
otro script que --file
otro ... Algún día invertiré en hacer que mi código desordenado se convierta en un paquete .
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))
}
})()
Here hay una solución simple para el problema. Este comando:
script.dir <- dirname(sys.frame(1)$ofile)
devuelve la ruta del archivo de script actual. Funciona después de guardar el script.
#!/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=''/''))
frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])
Sin embargo, no me preguntes cómo funciona, porque he olvidado: /