Как установить рабочий каталог в текущую папку, Rstudio? [Дубликат]

Просто добавление к исходному ответу. Хотя это будет работать:

MethodInfo method = typeof(Sample).GetMethod("GenericMethod");
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);

Также немного опасно, что вы теряете проверку времени компиляции для GenericMethod. Если вы позже выполните рефакторинг и переименуете GenericMethod, этот код не заметит и не будет работать во время выполнения. Кроме того, если есть какая-либо пост-обработка сборки (например, обфускация или удаление неиспользуемых методов / классов), этот код также может сломаться.

Итак, если вы знаете метод, с которым вы связываетесь во время компиляции , и это не называется миллионы раз, поэтому накладные расходы не имеют значения, я бы изменил этот код:

Action<> GenMethod = GenericMethod<int>;  //change int by any base type 
                                          //accepted by GenericMethod
MethodInfo method = this.GetType().GetMethod(GenMethod.Method.Name);
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);

Хотя вы не очень красивы, у вас есть ссылка времени компиляции на GenericMethod здесь, и если вы рефакторируете, удаляете или делаете что-либо с помощью GenericMethod, этот код будет продолжать работать или, по крайней мере, ломаться во время компиляции (если, например, вы удалите GenericMethod).

Другой способ сделать то же самое - создать новый класс-оболочку и создать его через Activator. Я не знаю, есть ли лучший способ.

197
задан Frank 29 November 2009 в 14:58
поделиться

23 ответа

Я бы использовал вариант подхода @ steamer25. Дело в том, что я предпочитаю получать последний скрипт, даже когда мой сеанс был запущен через Rscript. Следующий фрагмент, если он включен в файл, предоставит переменную thisScript, содержащую нормализованный путь скрипта. Я признаю (ab) использование source'ing, поэтому иногда я вызываю Rscript и скрипт, предоставленный в --file аргументе, источник другого сценария, который источает другой ... Когда-нибудь я буду инвестировать в превращение моего грязного кода в пакет .

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))
  }
})()
1
ответ дан Ailton Andrade de Oliveira 18 August 2018 в 22:26
поделиться

Я просто сам это сделал. Чтобы обеспечить переносимость вашего скрипта, всегда начинайте его с:

wd <- setwd(".")
setwd(wd)

Это работает, потому что «.» переводится как команда Unix $ PWD. Присвоение этой строки объекту-символу позволяет затем вставить этот объект-символ в setwd () и Presto , ваш код будет всегда запускаться с его текущим каталогом в качестве рабочего каталога, независимо от того, на чьей машине он включен или где в файловой структуре он находится. (Дополнительный бонус: wd-объект может использоваться с file.path () (то есть file.path (wd, «output_directory»), чтобы создать стандартный выходной каталог независимо от пути к файлу, ведущего к вашей именованной директории. Это требует, чтобы вы создали новый каталог, прежде чем ссылаться на него таким образом, но этому тоже может помочь объект wd.

В качестве альтернативы следующий код выполняет то же самое:

wd <- getwd()
setwd(wd)

или, если вам не нужен путь к файлу в объекте, вы можете просто:

setwd(".")
8
ответ дан Andrew Moffat Jr. 18 August 2018 в 22:26
поделиться
  • 1
    Неа. Это находит каталог процесса, а не самого файла. – user1071847 9 December 2016 в 21:45
  • 2
    Это работало для меня в Windows с RStudio в интерактивном режиме. – Contango 8 August 2017 в 07:00

99% случаев, которые вы могли бы просто использовать:

sys.calls()[[1]] [[2]]

Он не будет работать для сумасшедших вызовов, где сценарий не является первым аргументом, то есть source(some args, file="myscript"). Используйте @ hadley в этих причудливых случаях.

1
ответ дан antonio 18 August 2018 в 22:26
поделиться

Мне понравилось решение steamer25, поскольку оно кажется самым надежным для моих целей. Однако при отладке в RStudio (в окнах) путь не будет установлен правильно. Причина заключается в том, что если в RStudio установлена ​​точка останова, в поиске файла используется альтернативная команда «отладочный источник», которая устанавливает путь к сценарию несколько иначе. Вот окончательная версия, которую я сейчас использую, которая учитывает это альтернативное поведение в RStudio при отладке:

# @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))
        }
    }
}
6
ответ дан aprstar 18 August 2018 в 22:26
поделиться
  • 1
    источник в Rstudio дал forile для меня, но debugSource дал fileName, так что ваше решение работает хорошо, но комментарии кода не совсем правильные в моем случае – Mark Adamson 7 July 2016 в 13:32
  • 2
    Это работает для меня, когда я выполняю в cmd. – RAAAAM 19 December 2017 в 13:45

Мне нравится этот подход:

this.file <- sys.frame(tail(grep('source',sys.calls()),n=1))$ofile
this.dir <- dirname(this.file)
2
ответ дан beroe 18 August 2018 в 22:26
поделиться

Удивительно, что в R нет структуры типа «$ 0»! Вы можете сделать это с помощью вызова system () для сценария bash, написанного в R:

write.table(c("readlink -e $0"), file="scriptpath.sh",col=F, row=F, quote=F)
thisscript <- system("sh scriptpath.sh", intern = TRUE)

. Затем просто разделите имя scriptpath.sh для other.R

splitstr <- rev(strsplit(thisscript, "\\/")[[1]])
otherscript <- paste0(paste(rev(splitstr[2:length(splitstr)]),collapse="/"),"/other.R")
0
ответ дан bruce.moran 18 August 2018 в 22:26
поделиться

Это работает для меня

library(rstudioapi)    
rstudioapi::getActiveDocumentContext()$path
12
ответ дан ColinTea 18 August 2018 в 22:26
поделиться

Ответ rakensi из Получение пути к скрипту R является самым правильным и действительно блестящим IMHO. Тем не менее, это все еще хак, включающий фиктивную функцию. Я цитирую его здесь, чтобы облегчить его поиск другими.

sourceDir & lt; - getSrcDirectory (function (dummy) {dummy})

Это дает каталог файла, в котором размещен оператор (где определена фиктивная функция). Затем он может использоваться для установки рабочей директории и использования относительных путей, например

setwd(sourceDir)
source("other.R")

, или для создания абсолютных путей

 source(paste(sourceDir, "/other.R", sep=""))
11
ответ дан cuffel 18 August 2018 в 22:26
поделиться
  • 1
    Для меня ваше решение было лучшим. Специально потому, что он может быть применен к Блестящему приложению, а другой - к ссылке. – jcarlos 18 April 2016 в 11:30
  • 2
    Здесь getSrcDirectory - utils :: getSrcDirectory – ecerulm 25 October 2016 в 07:53
  • 3
    Это может хорошо работать под Linux / Mac, но это не сработало для меня в сеансе RStudio под Windows. sourceDir пусто. – Contango 8 August 2017 в 06:48
  • 4
    @Contango на интерактивном терминале, нет пути !!! Вам нужен путь к файлу. – pommedeterresautee 4 January 2018 в 11:18

Это работает для меня. Просто выгружайте его из аргументов командной строки, удаляет ненужный текст, создает имя dirname и, наконец, получает полный путь от этого:

args <- commandArgs(trailingOnly = F)  
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))
10
ответ дан eddi 18 August 2018 в 22:26
поделиться

Вы можете обернуть r-скрипт в сценарии bash и получить путь к скрипту как переменную bash следующим образом:

#!/bin/bash
     # [environment variables can be set here]
     path_to_script=$(dirname $0)

     R --slave<<EOF
        source("$path_to_script/other.R")

     EOF
1
ответ дан ennuikiller 18 August 2018 в 22:26
поделиться
  • 1
    Это требует, чтобы у вас был путь к скрипту. Это не позволяет вам создать действительно портативный R-скрипт, который может запускаться из любого места. – Etienne Low-Décarie 3 April 2012 в 19:19
  • 2
    @ EtienneLow-Décarie Это не требует пути к скрипту, он получает его от bash. Основная проблема заключается в том, что это не надежный способ получить путь. Что-то вроде этого предпочтительнее, как в stackoverflow.com/questions/59895/… path_to_script = & quot; $ (cd & quot; $ (dirname & quot; $ {BASH_SOURCE [0]} & quot;) & quot; & amp; pwd) & quot; – John Haberstroh 28 August 2017 в 21:00

Здесь существует простое решение задачи. Эта команда:

script.dir <- dirname(sys.frame(1)$ofile)

возвращает путь к текущему файлу скрипта. Он работает после сохранения сценария.

78
ответ дан Frank 18 August 2018 в 22:26
поделиться
  • 1
    Это не работает для меня. Я запускаю R в Windows. Есть идеи? – ehsan88 25 September 2014 в 13:38
  • 2
    Error in sys.frame(1) : not that many frames on the stack – B.Mr.W. 13 January 2015 в 05:40
  • 3
    Получил ту же ошибку, с сохраненным скриптом и свежей установкой и запуском R 3.2.0 на окнах ... – RalfB 20 May 2015 в 09:57
  • 4
    Такая же ошибка в Linux – patapouf_ai 11 June 2015 в 12:07
  • 5
    Эта ошибка возникает при попытке выполнить dirname(sys.frame(1)$ofile) непосредственно из Rstudio. Он работает нормально, когда сценарий выполняется с использованием источника («other.R»), а dirname(sys.frame(1)$ofile) находится внутри "other.R". – Murta 14 July 2015 в 23:39
frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])

Не спрашивайте меня, как это работает, потому что я забыл: /

32
ответ дан hadley 18 August 2018 в 22:26
поделиться
  • 1
    В каком контексте это работает? print (sys.frames ()) при запуске запускает NULL. – Suppressingfire 30 November 2009 в 06:21
  • 2
    @Suppressingfire: sys.frames возвращает среды стека вызовов, поэтому это действительно имеет смысл при вызове функции. Попробуйте, например, foo <- function() {bar <- function() print(sys.frames()); bar()}; foo(). Я не могу понять код @ hadley, хотя в среде нет члена ofile. – Richie Cotton 30 November 2009 в 12:27
  • 3
    Вы должны указать файл в i.e, если я сохраню этот код, тогда запустите source("~/code/test.r"), PATH будет установлено на ~/desktop. Если вы просто оцените его на верхнем уровне, он вернет NULL. – hadley 30 November 2009 в 17:24
  • 4
    R 2.6.2. почти два года. Получите более новую версию! – hadley 1 December 2009 в 16:27
  • 5
    Это не отвечает на мой вопрос. Мне нужно автоматически найти & quot; other.R & quot; файл. x$ofile не определено, поэтому frame_files пуст. – Frank 4 December 2009 в 17:08
  • 6

См. findSourceTraceback() пакета R.utils , который

Находит все объекты srcfile, сгенерированные источником () во всех кадрах вызовов. Это позволяет узнать, какие файлы в настоящее время написаны с помощью source ().

1
ответ дан HenrikB 18 August 2018 в 22:26
поделиться

Подход Steamer25 работает, но только если в пути нет пробелов. На macOS по крайней мере cmdArgs[match] возвращает что-то вроде /base/some~+~dir~+~with~+~whitespace/ для /base/some\ dir\ with\ whitespace/.

Я работал вокруг этого, заменив «~ + ~» простым пробелом перед его возвратом.

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))
  }
}

Очевидно, вы все равно можете расширить блокировку else, как это сделал aprstar.

0
ответ дан iball 18 August 2018 в 22:26
поделиться

Все в одном!

#' current script file (in full path)
#' @param
#' @return
#' @examples
#' works with Rscript, source() or in RStudio Run selection
#' @export
csf <- function() {
    # http://stackoverflow.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://stackoverflow.com/a/35842176/2292993  
                return(normalizePath(rstudioapi::getActiveDocumentContext()$path))
            }
        }
    }
}
8
ответ дан Jerry T 18 August 2018 в 22:26
поделиться
  • 1
    Не работает с интерактивной сессией R; Я получаю: `` `& gt; источник («csf.R») & gt; csf () Ошибка: RStudio не работает `` ` – ManicMailman 6 July 2017 в 23:57

Я завернул и расширил ответы на этот вопрос в новую функцию thisfile() в rprojroot . Также работает для вязания с knitr.

4
ответ дан Kayle Sawyer 18 August 2018 в 22:26
поделиться

У меня были проблемы с реализациями, описанными выше, так как мой скрипт управляется из символического каталога или, по крайней мере, поэтому я думаю, что вышеупомянутые решения не сработали для меня. В соответствии с ответом @ ennuikiller я завернул свой Rscript в bash. Я устанавливаю переменную пути с помощью pwd -P, которая разрешает символические структуры каталогов. Затем передайте путь в 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)
1
ответ дан Luke Singham 18 August 2018 в 22:26
поделиться

Если вместо скрипта foo.R, зная его местоположение пути, если вы можете изменить свой код, чтобы всегда ссылаться на все пути source 'd от общего root, то это может быть большой помощью:

Учитывая

  • /app/deeply/nested/foo.R
  • /app/other.R

Это будет работать

#!/usr/bin/env Rscript
library(here)
source(here("other.R"))

Для определения корней проекта см. https://krlmlr.github.io/rprojroot/ .

0
ответ дан mmell 18 August 2018 в 22:26
поделиться

Снятый вариант ответа Supressingfire:

source_local <- function(fname){
    argv <- commandArgs(trailingOnly = FALSE)
    base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
    source(paste(base_dir, fname, sep="/"))
}
12
ответ дан momeara 18 August 2018 в 22:26
поделиться
  • 1
    Это не сработало рекурсивно; файл I source ищет файл данных (но в неправильном каталоге). – The Unfun Cat 5 May 2015 в 13:38

Обратите внимание, что пакет getopt предоставляет функцию get_Rscript_filename, которая просто использует то же самое решение, представленное здесь, но уже написано для вас в стандартном модуле R, поэтому вам не нужно копировать и вставлять «get script» путь "в каждый скрипт, который вы пишете.

2
ответ дан Ryan Thompson 18 August 2018 в 22:26
поделиться
  • 1
    Он всегда возвращает NA, даже если я создаю скрипт, который печатает свой вывод, а затем вызывает сценарий, например. с R -e "library(getopt); testscript.R" – f1r3br4nd 20 February 2018 в 18:56
  • 2
    Как следует из названия функции, вам нужно запустить скрипт, используя Rscript. – Ryan Thompson 21 February 2018 в 01:42
  • 3
    Ах, ох. Благодарю. – f1r3br4nd 23 February 2018 в 02:49

Я не мог заставить решение Suppressingfire работать, когда «источник» с консоли R.

Лучшее из обоих миров?

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))
        }
}
37
ответ дан steamer25 18 August 2018 в 22:26
поделиться
  • 1
    Мне это нравится, потому что он работает как с Rscript, так и с source() внутри R. Я предлагаю сделать normalizePath() в обеих версиях, чтобы он дал полный путь в обоих случаях. – wch 12 November 2014 в 20:57
  • 2
    Это единственное, что сработало. Обратите внимание, что для этого library(base) мне понадобилось время, чтобы понять, что LOL – O.rka 4 October 2016 в 18:32
  • 3
    вы сэр получите мой голос, потому что это решение, которое сработало для меня – Vince W. 19 March 2018 в 05:30

Вы можете использовать функцию commandArgs, чтобы получить все параметры, которые были переданы Rscript, фактическому интерпретатору R и найти их для --file=. Если ваш скрипт был запущен с пути или был запущен с полным путем, script.name ниже начнется с '/'. В противном случае это должно быть относительно cwd, и вы можете выполнить два пути, чтобы получить полный путь.

Edit: похоже, что вам понадобится только script.name выше и снять финальную составляющую пути. Я удалил ненужный образец cwd() и очистил основной скрипт и отправил свой other.R. Просто сохраните этот скрипт и скрипт other.R в том же каталоге, chmod +x, и запустите основной скрипт.

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 <- paste(sep="/", script.basename, "other.R")
print(paste("Sourcing",other.name,"from",script.name))
source(other.name)

other.R :

print("hello")

output :

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"

Это то, что я считаю дехман ищет.

53
ответ дан Suppressingfire 18 August 2018 в 22:26
поделиться
  • 1
    Что с понижением? – Suppressingfire 29 November 2009 в 21:05
  • 2
    Я сбился с толку, потому что ваша техника не работает с source, поскольку я думал, что OP хочет - но, возможно, я неправильно прочитал его / ее требование. Но я не могу un-downmod :( Извините! – hadley 30 November 2009 в 17:26
  • 3
    Но на самом деле, он отлично работает с источником! Просто source (other.name), и он работает правильно. – Suppressingfire 1 December 2009 в 01:22
  • 4
    Я думаю, может быть, мы говорим в разных целях. Я думаю, что мы понимаем, что дехман заинтересован в этом. – Suppressingfire 1 December 2009 в 01:23
  • 5
    Для конкатенации путей лучше использовать other.name <- file.path(script.basename, "other.R") – Jason 9 September 2014 в 15:34
#!/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='/'))
0
ответ дан wildloop 18 August 2018 в 22:26
поделиться
  • 1
    Я все еще получаю ошибку & quot; Ошибка в sys.frame (1): не так много кадров в стеке & quot; – Michael Barton 31 October 2017 в 19:47
Другие вопросы по тегам:

Похожие вопросы: