同じディレクトリにあるfoo.R
別の script を含むというスクリプトがあります。other.R
#!/usr/bin/env Rscript
message("Hello")
source("other.R")
しかし、現在の作業ディレクトリが何であれ、R
それを見つけたいです。other.R
つまり、foo.R
独自のパスを知る必要があります。どうやってやるの?
この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 が求めているものだと私は信じています。
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))
}
}
frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])
私は忘れてしまったので、それがどのように機能するか私に聞かないでください:/
Get path of an R scriptからのrakensiの答えは、最も正確で本当に素晴らしい私見です。それでも、ダミー機能を組み込んだハックです。他の人が見つけやすくするために、ここで引用します。
sourceDir <- getSrcDirectory(function(dummy) {dummy})
これにより、ステートメントが配置されたファイルのディレクトリが得られます (ダミー関数が定義されている場所)。次に、作業ディレクトリを設定し、相対パスを使用するために使用できます。
setwd(sourceDir)
source("other.R")
または絶対パスを作成する
source(paste(sourceDir, "/other.R", sep=""))
私のオールインワン!(--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)
}
}
}
}
}
Supressingfireの回答のスリム化されたバリアント:
source_local <- function(fname){
argv <- commandArgs(trailingOnly = FALSE)
base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
source(paste(base_dir, fname, sep="/"))
}
これは私のために働きます。コマンドライン引数からそれを取得し、不要なテキストを取り除き、dirnameを実行し、最後にそこからフルパスを取得します。
args <- commandArgs(trailingOnly = F)
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))
私はこのアプローチが好きです:
this.file <- sys.frame(tail(grep('source',sys.calls()),n=1))$ofile
this.dir <- dirname(this.file)
次のように、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
R.utilsパッケージfindSourceTraceback()
の参照。
すべての呼び出しフレームで source() によって生成されたすべての 'srcfile' オブジェクトを検索します。これにより、source() によって現在スクリプト化されているファイルを見つけることができます。
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 ブロックを拡張できます。
単純に使用できるケースの 99%:
sys.calls()[[1]] [[2]]
スクリプトが最初の引数ではないクレイジーな呼び出し、つまりsource(some args, file="myscript")
. これらの派手なケースでは @hadley を使用してください。
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')
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_SRC
Rscript
$ export R_SRC=/path/to/R/code/
$ Rscript /path/to/R/code/foo.R
#!/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='/'))