283

同じディレクトリにあるfoo.R別の script を含むというスクリプトがあります。other.R

#!/usr/bin/env Rscript
message("Hello")
source("other.R")

しかし、現在の作業ディレクトリが何であれ、Rそれを見つけたいです。other.R

つまり、foo.R独自のパスを知る必要があります。どうやってやるの?

4

30 に答える 30

80

このcommandArgs関数を使用して、Rscript によって実際の R インタープリターに渡されたすべてのオプションを取得し、--file=. スクリプトがパスから起動された場合、またはフル パスで起動された場合、script.name以下は'/'. それ以外の場合は、 に対して相対的である必要がありcwd、2 つのパスを連結して完全なパスを取得できます。

編集:上記のみが必要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 <- file.path(script.basename, "other.R")
print(paste("Sourcing",other.name,"from",script.name))
source(other.name)

その他の R :

print("hello")

出力:

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"

これこそが、dehmann が求めているものだと私は信じています。

于 2009-11-29T15:04:28.603 に答える
60

R コンソールから「source」するときに、Suppressingfire のソリューションを機能させることができませんでした。
Rscriptを使用している場合、ハドリーのソリューションを機能させることができませんでした。

両方の長所?

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))
        }
}
于 2013-03-12T23:00:00.540 に答える
38
frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])

私は忘れてしまったので、それがどのように機能するか私に聞かないでください:/

于 2009-11-29T19:21:05.930 に答える
27

Get path of an R scriptからのrakensiの答えは、最も正確で本当に素晴らしい私見です。それでも、ダミー機能を組み込んだハックです。他の人が見つけやすくするために、ここで引用します。

sourceDir <- getSrcDirectory(function(dummy) {dummy})

これにより、ステートメントが配置されたファイルのディレクトリが得られます (ダミー関数が定義されている場所)。次に、作業ディレクトリを設定し、相対パスを使用するために使用できます。

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

または絶対パスを作成する

 source(paste(sourceDir, "/other.R", sep=""))
于 2016-03-29T05:39:18.530 に答える
18

私のオールインワン!(--2019 年 1 月 9 日、RStudio コンソールに対応するように更新)

#' current script file (in full path)
#' @description current script file (in full path)
#' @examples
#' works with Rscript, source() or in RStudio Run selection, RStudio Console
#' @export
ez.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
                pth = rstudioapi::getActiveDocumentContext()$path
                if (pth!='') {
                    return(normalizePath(pth))
                } else {
                    # RStudio Console
                    tryCatch({
                            pth = rstudioapi::getSourceEditorContext()$path
                            pth = normalizePath(pth)
                        }, error = function(e) {
                            # normalizePath('') issues warning/error
                            pth = ''
                        }
                    )
                    return(pth)
                }
            }
        }
    }
}
于 2016-04-21T18:24:36.967 に答える
13

Supressingfireの回答のスリム化されたバリアント:

source_local <- function(fname){
    argv <- commandArgs(trailingOnly = FALSE)
    base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
    source(paste(base_dir, fname, sep="/"))
}
于 2011-06-23T23:31:06.010 に答える
11

これは私のために働きます。コマンドライン引数からそれを取得し、不要なテキストを取り除き、dirnameを実行し、最後にそこからフルパスを取得します。

args <- commandArgs(trailingOnly = F)  
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))
于 2011-09-28T15:26:48.273 に答える
2

私はこのアプローチが好きです:

this.file <- sys.frame(tail(grep('source',sys.calls()),n=1))$ofile
this.dir <- dirname(this.file)
于 2014-12-16T22:43:56.657 に答える
2

次のように、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
于 2009-11-29T14:12:46.230 に答える
1

R.utilsパッケージfindSourceTraceback()の参照。

すべての呼び出しフレームで source() によって生成されたすべての 'srcfile' オブジェクトを検索します。これにより、source() によって現在スクリプト化されているファイルを見つけることができます。

于 2014-05-18T17:02:56.390 に答える
1

Steamer25 のアプローチは機能しますが、パスに空白がない場合のみです。macOS では、少なくともforの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))
  }
}

明らかに、aprstar のように else ブロックを拡張できます。

于 2017-07-29T12:37:54.183 に答える
1

単純に使用できるケースの 99%:

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

スクリプトが最初の引数ではないクレイジーな呼び出し、つまりsource(some args, file="myscript"). これらの派手なケースでは @hadley を使用してください。

于 2016-11-25T13:13:47.990 に答える
0

sys.frame(1)上記の回答に基づいて構築するために、安全チェックとして、(何らかの理由で)失敗した場合 (何らかの理由で) ファイルを見つけるようにユーザーに求めるラッパーを追加するinteractive() == TRUEか、ソーススクリプトがメインスクリプトの場所にない場合があります。であることを期待しています。

fun_path = tryCatch(expr = 
                      {file.path(dirname(sys.frame(1)$ofile), "foo.R")},
                    error = function(e){'foo.R'}
                    )
if(!file.exists(fun_path))
{
  msg = 'Please select "foo.R"'
  # ask user to find data
  if(Sys.info()[['sysname']] == 'Windows'){#choose.files is only available on Windows
    message('\n\n',msg,'\n\n')
    Sys.sleep(0.5)#goes too fast for the user to see the message on some computers
    fun_path  = choose.files(
      default = file.path(gsub('\\\\', '/', Sys.getenv('USERPROFILE')),#user
                          'Documents'),
      caption = msg
    )
  }else{
    message('\n\n',msg,'\n\n')
    Sys.sleep(0.5)#goes too fast for the user to see the message on some computers
    fun_path = file.choose(new=F)
  }
}
#source the function
source(file = fun_path, 
       encoding = 'UTF-8')
于 2021-12-01T12:18:51.287 に答える
0

HPC クラスター環境で作業しています。本番環境とは別の場所でコードを開発しています。開発中、私は通常、コマンド ラインから対話的に R を呼び出しています ( RStudio は使用しません)。たくさんのsource("foo.R")ことが起こっています。

実動実行中、私は通常、さまざまなパラメーターを試し、各パラメーターのセットを個別のディレクトリーで実行する bash スクリプトを作成します。bash スクリプトは、ワークロード マネージャー (つまり SLURM) を利用します。この環境では、環境変数を設定するのは簡単です。これを念頭に置いて、以下の解決策が私に最適です。

その他.R

my_message <- function(){
return("R is awkward")
}

foo.R

srcpath = Sys.getenv("R_SRC")
# Check if runnning w/o setting R_SRC - presumably done in directory of development, i.e. /path/to/R/code
if(srcpath == ""){
    srcpath="./"
}
source(sprintf("%s/other.R", srcpath))
string = my_message()
print(string)

これを R インタラクティブ シェルから 内/path/to/R/codeで実行する場合は、次のようにします。

> source("foo.R")

インタラクティブ シェルや から実行していない場合は、最初に/path/to/R/code環境変数を設定してから、R_SRCRscript

$ export R_SRC=/path/to/R/code/
$ Rscript /path/to/R/code/foo.R
于 2020-08-26T04:05:22.740 に答える
0
#!/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='/'))
于 2014-11-23T14:35:01.393 に答える