Получить имя файла и путь к файлу `source`d

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

Фон:

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

Итак, строка типа

    setwd (my.own.path ()) 

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

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

Ответ 1

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

Ответ 2

Начиная с предложений gsk3 Seb, вот идея:

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

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

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

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

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

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

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

Усовершенствования приветствуются!


Update:

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

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

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


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

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

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

Ответ 3

Вы можете использовать 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"), и я не тестировал, что произойдет, если у вас есть один файл sourcing другой файл &mdash, но вы могли бы построить решение поверх это.

Ответ 4

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

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

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

Ответ 5

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

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

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

Ответ 6

Этот ответ работает для 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
    }
}