私はと呼ばれるスクリプト持っているfoo.R
別のスクリプトが含まother.R
同じディレクトリにあります、:
#!/usr/bin/env Rscript
message("Hello")
source("other.R")
しかし、私は現在の作業ディレクトリが何であっR
てother.R
もそれを見つけたいです。
つまり、foo.R
独自のパスを知る必要があります。どうやってやるの?
私はと呼ばれるスクリプト持っているfoo.R
別のスクリプトが含まother.R
同じディレクトリにあります、:
#!/usr/bin/env Rscript
message("Hello")
source("other.R")
しかし、私は現在の作業ディレクトリが何であっR
てother.R
もそれを見つけたいです。
つまり、foo.R
独自のパスを知る必要があります。どうやってやるの?
回答:
ここに問題の簡単な解決策があります。このコマンド:
script.dir <- dirname(sys.frame(1)$ofile)
現在のスクリプトファイルのパスを返します。スクリプトが保存された後に機能します。
dirname(sys.frame(1)$ofile)
Rstudioから直接実行しようとしたときに発生します。source( "other.R")を使用してスクリプトが実行され、dirname(sys.frame(1)$ofile)
内部にある場合は問題なく動作し"other.R"
ます。
NULL
これをサーバーに配置するとゲル化します。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が探しているものだと思います。
source
OPが望んでいたように機能しないので、私はダウンモッド化しました-しかし、おそらく彼/彼女の要件を誤って読みました。しかし、私はダウンモードを解除することはできません:(すみません!
other.name <- file.path(script.basename, "other.R")
commandArgs(trailingOnly = FALSE)
光沢のあるアプリケーションでserver.R内で実行しようとすると、が表示されます[1] "RStudio" "--interactive"
。呼び出し元のディレクトリに関する情報はありません。
Rコンソールから「ソース」するときに、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))
}
}
Rscript
とsource()
R.私がやってお勧めしたいの中normalizePath()
には、両方のケースで完全なパスを与えるように、両方のバージョンに。
library(base)
は、それを理解するのに少し時間がかかりました
source(file.path(dirname(thisFile()), "other.R"))
れfoo.R
ます。これは私にとってはうまくいきます。
main.R
をソース化するhelper.R
としますthisFile()
。main.R
ではなくのパスをフェッチしますhelper.R
。ここで何かヒントはありますか?
frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])
私は忘れてしまったので、それがどのように機能するか私に尋ねないでください:/
sys.frames
呼び出しスタックの環境を返すため、関数から呼び出された場合にのみ意味があります。たとえば、を試してくださいfoo <- function() {bar <- function() print(sys.frames()); bar()}; foo()
。環境にofile
メンバーがいないため、@ hadleyのコードを理解できません。
source("~/code/test.r")
、PATH
に設定され~/desktop
ます。最上位で評価すると、NULLが返されます。
x$ofile
は未定義なのでframe_files
、空です。
これは私のために働く
library(rstudioapi)
rstudioapi::getActiveDocumentContext()$path
Error: RStudio not running
。
""
、私の場合は正しい結果が得られません
ラーケンシーの答えRスクリプトのパスの取得からは、最も正確で本当に素晴らしいIMHOです。それでも、それはまだダミー関数を組み込んだハックです。他の人が見つけやすくするために、ここでは引用しています。
sourceDir <-getSrcDirectory(function(dummy){dummy})
これにより、ステートメントが配置された(ダミー関数が定義されている)ファイルのディレクトリが得られます。次に、作業ディレクトリを設定し、相対パスを使用するために使用できます。
setwd(sourceDir)
source("other.R")
または絶対パスを作成する
source(paste(sourceDir, "/other.R", sep=""))
sourceDir
空白だった。
character(0)
。提案?
私のオールインワン!(2019年1月1日、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)
}
}
}
}
}
この質問への回答をまとめ、rprojrootの新しい関数thisfile()
に拡張しました。との編み物にも使えknitr
ます。
私の目的にとって最も堅牢なように見えるので、steamer25のソリューションが気に入りました。ただし、RStudio(Windows)でデバッグする場合、パスが正しく設定されませんでした。その理由は、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))
}
}
}
私は、この質問からほとんどすべてを試みRスクリプトのパスを取得、現在のスクリプトのパスを取得し、現在の.Rファイルの場所探しとRstudioでソースファイルの場所に作業ディレクトリを設定するためのRコマンドを、しかし最後に手動で自分自身を発見しましたCRANテーブルを閲覧して見つけた
scriptName
図書館
current_filename()
RStudioでソースを作成するとき、およびRまたはRScript実行可能ファイルを介して呼び出すときに、スクリプトの適切な完全パスを返す関数を提供します。
Package ‘scriptName’ was removed from the CRAN repository.
-今何?:o
私にもこの問題があり、上記の解決策はどれもうまくいきませんでした。多分source
そのようなもので、しかしそれは十分に明確ではありませんでした。
私はこれをエレガントな解決策として見つけました:
paste0(gsub("\\", "/", fileSnapshot()$path, fixed=TRUE),"/")
その中で重要なのはfileSnapshot()
、ファイルに関する多くの情報を提供することです。8つの要素のリストを返します。path
リスト要素として選択すると、パスは\\
セパレータとして返されるので、コードの残りの部分はそれを変更するだけです。
これがお役に立てば幸いです。
次のように、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
私はこのアプローチが好きです:
this.file <- sys.frame(tail(grep('source',sys.calls()),n=1))$ofile
this.dir <- dirname(this.file)
私はこれを自分で解決しました。スクリプトの移植性を確保するために、常に次のことから始めてください。
wd <- setwd(".")
setwd(wd)
「。」のために機能します。Unixコマンド$ PWDのように変換します。この文字列を文字オブジェクトに割り当てると、その文字オブジェクトをsetwd()およびPrestoに挿入できますのコードは常に、現在のディレクトリを作業ディレクトリとして実行します。あります。(追加のボーナス:wdオブジェクトをfile.path()(つまり、file.path(wd、 "output_directory")と一緒に使用して、指定したディレクトリへのファイルパスに関係なく標準出力ディレクトリを作成できます。この方法では、この方法で参照する前に新しいディレクトリを作成する必要がありますが、これもwdオブジェクトで補助できます。
または、次のコードはまったく同じことを実行します。
wd <- getwd()
setwd(wd)
または、オブジェクトのファイルパスが必要ない場合は、次のように簡単にできます。
setwd(".")
getoptパッケージが提供するget_Rscript_filename
関数は、ここで示したものと同じソリューションを使用しますが、標準のRモジュールですでに作成されているため、「スクリプトパスの取得」関数をすべてのスクリプトにコピーして貼り付ける必要はありません。あなたが書く。
R -e "library(getopt); testscript.R"
Rscript
。
スクリプトがシンボリックリンクディレクトリから操作されているため、上記の実装に問題がありました。少なくとも、上記の解決策がうまくいかなかったのはそのためです。@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)
@ steamer25のアプローチのバリアントを使用します。ポイントは、セッションがRscriptを介して開始された場合でも、最後のソーススクリプトを取得したいということです。次のスニペットをファイルに含めるthisScript
と、スクリプトの正規化されたパスを含む変数が提供されます。私はソースの(乱用)使用を告白します。そのため、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))
}
})()
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))
}
}
もちろん、aprstarのようにelseブロックを拡張することもできます。
スクリプトではなく、foo.R
そのパスの場所がわかっている場合、コードを変更してsource
、コモンからのすべての'dパスを常に参照するroot
ようにできる場合、これらは非常に役立ちます。
与えられた
/app/deeply/nested/foo.R
/app/other.R
これは動作します
#!/usr/bin/env Rscript
library(here)
source(here("other.R"))
プロジェクトのルートを定義する方法については、https://rprojroot.r-lib.org/を参照してください。
#!/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='/'))
Rには '$ 0'タイプの構造はありません。Rで書かれたbashスクリプトへのsystem()呼び出しでそれを行うことができます:
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")
readLink: illegal option -- e usage: readLink [-FlLnqrsx] [-f format] [-t timefmt] [file ...]
コールスタックを確認することで、実行中の各スクリプトのファイルパスを取得できます。最も有用な2つは、おそらく現在実行中のスクリプトか、最初に取得するスクリプト(エントリ)のどちらかです。
script.dir.executing = (function() return( if(length(sys.parents())==1) getwd() else dirname( Filter(is.character,lapply(rev(sys.frames()),function(x) x$ofile))[[1]] ) ))()
script.dir.entry = (function() return( if(length(sys.parents())==1) getwd() else dirname(sys.frame(1)$ofile) ))()