2012-01-12 10 views
18

¿Cómo puede un archivo source d Sweave d encontrar su propio camino?obtener el nombre de archivo y la ruta del archivo `source`d

Antecedentes:

yo trabajo mucho con las secuencias de comandos o archivos .R .Rnw. Mis proyectos están organizados en una estructura de directorio, pero la ruta del directorio base del proyecto varía con frecuencia entre diferentes computadoras (por ejemplo, porque solo hago parte del análisis de datos para otra persona, y su estructura de directorio es diferente a la mía: Tengo proyectos base directorios ~/Projects/StudentName/o ~/Projects/Studentname/Projectname y la mayoría de los estudiantes que solo tienen su proyecto generalmente lo tienen en ~/Measurements/o ~/DataAnalysis/o algo por el estilo, lo que no funcionaría para mí) .

Así que una línea como

setwd (my.own.path()) 

sería increíblemente útil, ya que permitiría a garantizar el directorio de trabajo es la ruta de la base del proyecto, independientemente de dónde ese proyecto en realidad es. Sin la necesidad de que el usuario piense en configurar el directorio de trabajo.

Déjenme aclarar: busco una solución que funcione presionando el editor/IDE source o Sweave Atajo de teclado del usuario irreflexivo.

+2

La opción 'chdir' de' source' es similar a la que está solicitando. – James

+1

Mi arreglo típico para esto es poner el directorio de proyectos de cada computadora en una variable de caracteres establecida en .Rprofile. –

+0

@James: Esa es una solución parcial. Si tengo que escribir 'source (" project/path/file.R ", chdir = TRUE)' No estoy mejor que escribiendo 'setwd (" project/path ") y presiono el atajo para interactuar (la mayoría de los usuarios) comenzará con un script, posiblemente 'source' y luego continuará más o menos de forma interactiva al ajustar/agregar al script o al archivo Sweave – cbeleites

Respuesta

10

Para su información, se knitrsetwd() al dir del archivo de entrada cuando (y sólo cuando) la evaluación de los trozos de código, es decir, si se llama a knit('path/to/input.Rnw'), el directorio de trabajo temporal habrá cambiado a path/to/. Si desea conocer el directorio de entrada en fragmentos de código, actualmente puede llamar a una función no exportada knitr:::input_dir() (puedo exportarla en el futuro).

+0

Querido Yihui, es bueno saberlo. No conocía 'knitr' y parece muy prometedor. – cbeleites

+0

Es genial que knitr tenga este comportamiento predeterminado inteligente. Sin embargo, 'knitr ::: input_dir()' se predetermina a "." incluso cuando se ejecuta un fragmento knitr en Rstudio. Mi flujo de trabajo es construir el script en Rstudio y solo tejer al final, por lo que 'knitr ::: input_dir()' no es suficiente. – Ruben

+0

@Ruben Creo que es un malentendido debido al hecho de que estaba usando RStudio: RStudio hace 'setwd()' (establece el directorio de trabajo en el directorio de su archivo de entrada) antes de llamar a 'knitr', y es por eso que ve '.', que es absolutamente correcto. Debe probarlo fuera de RStudio, p. ejecutarse en una biblioteca 'R terminal (knitr); knit ('path/to/input.Rnw') ', entonces verá' input_dir() 'es' ruta/a/' –

3

tengo ninguna solución directa de cómo obtener el directorio del propio archivo, pero si usted tiene un rango limitado de directorios y estructuras de directorios es probable que pueda utilizar

if(file.exists("c:/somedir")==TRUE){setwd("c:/somedir")} 

se puede consultar el patrón del directorio en cuestión y luego establecer el dir. ¿Esto te ayuda?

+0

Seb, lamentablemente los nombres de directorio que las diferentes personas prefieren parecen ser muy diferentes ... – cbeleites

+0

Podría buscar todo el árbol de directorios una vez, luego escriba el directorio resultante en un constante almacenado en .Rprofile? :-) –

+0

El tiempo necesario para buscar en todo el árbol de directorios debería enseñarle a cualquiera a organizarse con un directorio de Proyectos ;-) – cbeleites

11

A partir de sugerencias de Seb de GSK3, aquí está una idea:

  • la combinación de nombre de usuario (login) y una IP o nombre del equipo podría ser utilizado para seleccionar el directorio correcto.

que lleva a algo como:

setwd (switch (paste (Sys.info() [c ("user", "nodename")], collapse="."), 
      user.laptop = "~/Messungen", 
      user2.server = "~/Projekte/Projekt/", 
      )) 

Así que no es una solución automática, que

  • obras con source
  • obras con Sweave
  • siquiera funciona para interactivo sesiones donde los comandos se envían línea por línea

  • la combinación de user y nodename, por supuesto, tiene que ser específico

  • los caminos deben ser editado a mano, sin embargo.

Mejoras bienvenidas!


Actualización:

Gabor Grothendieck respondió lo siguiente a una pregunta relacionada con el r-ayuda hoy:

this.dir <- dirname(parent.frame(2)$ofile) 
setwd(this.dir) 

que trabajará para source.


Otra actualización: ahora hago la mayor parte del trabajo de análisis de datos en RStudio. Los proyectos de RStudio básicamente resuelven el problema: RStudio cambia el directorio de trabajo al directorio raíz del proyecto cada vez que cambio de proyecto.

Por lo tanto, puedo poner el directorio del proyecto lo más abajo posible (y los estudiantes también pueden poner su copia donde quieran) y sincronizar los archivos de datos y scripts/.Rnw a través del control de versiones (Usamos servidor privado de git). Los archivos del proyecto RStudio se mantienen fuera del control de versión, es decir, .gitignore contiene .Rproj.user.

Obviamente, en el proyecto, la estructura del directorio debe sincronizarse.

+0

Por el momento me quedaré con esto, ya que permite a los usuarios fácilmente (es decir, sin depender de una función 'setwd' de su editor) utilizar los archivos de forma interactiva mientras se desarrollan. Gracias por la contribución que me permitió tener esta idea. – cbeleites

+1

La primera solución no funciona en un entorno arbitrario, la solución de Grothendieck no funciona en mi mac (parent.frame() no tiene $ ofile). – Ruben

+0

@cbeleites En Rstudio en una máquina de Windows, este es el mensaje de error que aparece "Error en dirname (parent.frame (2) $ ofile): se espera un argumento de vector de caracteres" – MHH

4

Puede usar sys.calls() para obtener el comando utilizado para obtener el archivo. Entonces necesita un poco de engaño usando expresiones regulares para obtener la ruta, teniendo en cuenta que source("something/filename") podría haber usado la ruta absoluta o relativa. Aquí hay un primer intento de unir todas las piezas: intente insertar las siguientes líneas en la parte superior de un archivo fuente.

whereFrom=sys.calls()[[1]] 
# This should be an expression that looks something like 
# source("pathname/myfilename.R") 
whereFrom=as.character(whereFrom[2]) # get the pathname/filename 
whereFrom=paste(getwd(),whereFrom,sep="/") # prefix it with the current working directory 
pathnameIndex=gregexpr(".*/",whereFrom) # we want the string up to the final '/' 
pathnameLength=attr(pathnameIndex[[1]],"match.length") 
whereFrom=substr(whereFrom,1,pathnameLength-1) 
print(whereFrom) # or "setwd(whereFrom)" to set the working directory 

No es muy robusta — por ejemplo, se producirá un error en las ventanas con source("pathname\\filename"), y no he probado lo que sucede si usted tiene un archivo de abastecimiento otro archivo — pero que podría ser capaz de construir una solución en arriba de esto

2

Un problema adicional es que el directorio de trabajo es una variable global, que puede ser modificada por cualquier secuencia de comandos, por lo que si su secuencia de comandos llama a otra secuencia de comandos, tendrá que volver a configurar el wd. En rstudio utilizo Sesión -> Directorio de Trabajo Conjunto -> A Fuente de ubicación del archivo (lo sé, no es ideal), y luego mi script hace

wd = getwd() 
... 
source ("mySubDir/myOtherScript.R", chdir=TRUE); setwd (wd) 
... 
source ("anotherSubDir/anotherScript.R", chdir=TRUE); setwd (wd) 

De esta manera se puede mantener una pila de directorios de trabajo. Me encantaría ver esto implementado en el lenguaje mismo.

0

Esta respuesta funciona para source y también dentro de nvim-R - No tengo idea si funciona con knitr y cosas similares. Cualquier comentario apreciado.

Si tiene varias secuencias de comandos source, entre sí, es importante obtener la correcta. Es decir, el mayor i para el que existe sys.frame(i)$ofile.

get.full.path.to.this.sourced.script = function() {  
    for(i in sys.nframe():1) { # Go through all the call frames, 
           # in *reverse* order. 
     x = sys.frame(i)$ofile 
     if(!is.null(x))    # if $ofile exists, 
      return(normalizePath(x)) # then return the full absolute path 
    } 
} 
Cuestiones relacionadas