получить имя файла и путь к файлу `source`d - PullRequest
18 голосов
/ 12 января 2012

Как файл source d или Sweave d может найти свой собственный путь?

Справочная информация:

Я много работаю со скриптами .R или файлами .Rnw. Мои проекты организованы в структуру каталогов, но путь к базовому каталогу проекта часто различается на разных компьютерах (например, потому что я просто делаю части анализа данных для кого-то другого, а их структура каталогов отличается от моей: у меня есть базовые каталоги проектов ~ / Projects / StudentName / или ~ / Projects / Studentname / Projectname и большинство студентов, у которых есть только один проект, обычно имеют его в ~ / Measurements / или ~ / DataAnalysis / или что-то подобное - что мне не подойдет)

Итак, линия вроде

    setwd (my.own.path ()) 

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

Позвольте мне уточнить: я ищу решение, которое работает с нажатием комбинации клавиш / IDE source или Sweave сочетания клавиш бездумного пользователя.

Ответы [ 6 ]

12 голосов
/ 13 января 2012

Только к вашему сведению, knitr будет setwd() равным dir входного файла, когда (и только когда) оценивая куски кода, т.е. если вы вызываете knit('path/to/input.Rnw'), рабочий каталог будет временно переключен на path/to/,Если вы хотите узнать входной каталог в блоках кода, в настоящее время вы можете вызвать неэкспортированную функцию knitr:::input_dir() (я могу экспортировать ее в будущем).

11 голосов
/ 12 января 2012

Исходя из предложений Seb от gsk3, вот идея:

  • комбинация имени пользователя (логин) и IP или имени компьютера может использоваться для выбора правильного каталога.

Это приводит к чему-то вроде:

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

Итак, существует автоматическое решение, которое

  • работает с source
  • работает с Sweave
  • даже работает для интерактивных сеансов, где команды отправляются построчно

  • комбинация user и nodename, конечно, должна быть конкретной

  • пути нужно редактировать вручную.

Улучшения приветствуются!


Обновление:

Габор Гротендик ответил на следующий вопрос на r-help сегодня:

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

, который будет работать для source.


Еще одно обновление: сейчас я делаю большую часть работы по анализу данных в RStudio. Проекты RStudio в основном решают проблему: RStudio меняет рабочий каталог на корневой каталог проекта каждый раз, когда я переключаюсь между проектами.

Поэтому я могу расположить каталог проекта как можно ниже в моем дереве каталогов (и студенты также могут поместить свою копию куда угодно) и синхронизировать файлы данных и сценарии / .Rnw s с помощью контроля версий (мы используем частный сервер git). Файлы проекта RStudio хранятся вне контроля версий, т.е. .gitignore содержит .Rproj.user.

Очевидно, что в проекте, структура каталогов должна быть синхронизирована.

4 голосов
/ 02 августа 2013

Вы можете использовать sys.calls(), чтобы получить команду, используемую для получения файла.Затем вам понадобится немного хитрости, используя регулярные выражения для получения пути, учитывая, что source("something/filename") мог бы использовать либо абсолютный, либо относительный путь.Вот первая попытка собрать все части вместе: попробуйте вставить следующие строки вверху исходного файла.

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

Это не очень надежно - например, оно не работает в Windows с source("pathname\\filename")и я не проверял, что происходит, если у вас есть один файл из другого файла, но, возможно, вы сможете построить решение поверх этого.

3 голосов
/ 12 января 2012

У меня нет прямого решения, как получить каталог самого файла, но если у вас ограниченный диапазон каталогов и структур каталогов, вы, вероятно, можете использовать

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

Вы можете проверить шаблонкаталог, о котором идет речь, а затем установите каталог.Вам это поможет?

2 голосов
/ 07 сентября 2013

Дополнительная проблема заключается в том, что рабочий каталог является глобальной переменной, которая может быть изменена любым сценарием, поэтому, если ваш сценарий вызывает другой сценарий, ему придется установить обратно wd. В RStudio я использую Session -> Set Working Directory -> To Source File Location (я знаю, это не идеально), и тогда мой скрипт делает

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

Таким образом, можно поддерживать стек рабочих каталогов. Мне бы очень хотелось, чтобы это было реализовано на самом языке.

0 голосов
/ 16 мая 2017

Этот ответ работает для source, а также внутри nvim-R - я понятия не имею, работает ли он с knitr и подобными вещами. Любые отзывы приветствуются.

Если у вас есть несколько сценариев source, связанных друг с другом, важно получить правильный. То есть самый большой i, для которого существует 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
    }
}
...