web-dev-qa-db-ja.com

`source`dファイルのファイル名とパスを取得します

sourcedまたはSweavedファイルはどのようにして独自のパスを見つけることができますか?

バックグラウンド:

私は.Rスクリプトまたは.Rnwファイルをよく扱います。私のプロジェクトはディレクトリ構造で構成されていますが、プロジェクトのベースディレクトリのパスは、コンピュータごとに異なることがよくあります(たとえば、他の人のためにデータ分析の一部を実行するだけで、ディレクトリ構造が私のものとは異なるためです。プロジェクトのベースディレクトリがあります。 〜/ Projects/StudentName /または〜/ Projects/Studentname/Projectnameと、プロジェクトが1つしかないほとんどの学生は、通常、〜/ Measurements /または〜/ DataAnalysis /などの下にプロジェクトを持っています-これは私には機能しません)。

だから次のような行

    setwd (my.own.path ()) 

プロジェクトが実際にどこにあるかに関係なく、作業ディレクトリがプロジェクトのベースパスであることを確認できるため、非常に便利です。ユーザーが作業ディレクトリの設定を考える必要はありません。

明確にしましょう。私は、エディター/ IDEのsourceまたはSweaveキーボードショートカットを思いもよらないユーザーに押して動作するソリューションを探しています。

参考までに、コードチャンクを評価するとき(そしてそのときだけ)、つまりsetwd()を呼び出すと、作業ディレクトリにknitrが入力ファイルのディレクトリにknit('path/to/input.Rnw')します。一時的に_path/to/_に切り替えられます。コードチャンクの入力ディレクトリを知りたい場合は、現在、エクスポートされていない関数knitr:::input_dir()を呼び出すことができます(将来エクスポートする可能性があります)。

12
Yihui Xie

Gsk3のSebの提案から始めて、ここにアイデアがあります:

  • ユーザー名(ログイン)とIPまたはコンピューターの名前の組み合わせを使用して、適切なディレクトリを選択できます。

それは次のようなものにつながります:

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

つまり、自動ソリューションがあります。

  • sourceで動作します
  • Sweaveで動作します
  • コマンドが1行ずつ送信されるインタラクティブセッションでも機能します

  • もちろん、usernodenameの組み合わせは具体的である必要があります

  • ただし、パスは手動で編集する必要があります。

改善を歓迎します!


更新:

Gabor Grothendieckは、今日のr-helpに関する関連する質問に次のように答えました。

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

これはsourceで機能します。


別の更新:私は現在、RStudioでほとんどのデータ分析作業を行っています。 RStudioのプロジェクトは基本的に問題を解決します。RStudioは、プロジェクトを切り替えるたびに、作業ディレクトリをプロジェクトルートディレクトリに変更します。

したがって、プロジェクトディレクトリをディレクトリツリーの最下位に配置し(学生はコピーを好きな場所に配置することもできます)、バージョン管理を介してデータファイルとスクリプト/ .Rnwsを同期できます(プライベートを使用します) gitサーバー)。 RStudioプロジェクトファイルはバージョン管理の対象外になります。つまり、.gitignoreには.Rproj.userが含まれます。

明らかに、withinプロジェクトでは、ディレクトリ構造を同期する必要があります。

11
cbeleites

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
_

それほど堅牢ではありません。たとえば、source("pathname\\filename")のあるウィンドウでは失敗します。あるファイルが別のファイルを調達している場合にどうなるかはテストしていませんが、その上にソリューションを構築できる可能性があります。これの。

4

ファイル自体のディレクトリを取得する直接的な解決策はありませんが、ディレクトリとディレクトリ構造の範囲が限られている場合は、おそらく使用できます

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

問題のディレクトリのパターンを確認してから、ディレクトリを設定できます。これはあなたを助けますか?

3
Seb

追加の問題は、作業ディレクトリがグローバル変数であり、任意のスクリプトで変更できるため、スクリプトが別のスクリプトを呼び出す場合は、wdを元に戻す必要があることです。 RStudioでは、[セッション]-> [作業ディレクトリの設定]-> [ソースファイルの場所へ]を使用します(これは理想的ではありません)。

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

このようにして、作業ディレクトリのスタックを維持できます。これが言語自体で実装されることを望んでいます。

2
Paul Boersma

この回答はsourceでも機能し、_nvim-R_内でも機能します-knitrなどで機能するかどうかはわかりません。フィードバックをいただければ幸いです。

複数のスクリプトが互いにsource-している場合は、正しいスクリプトを取得することが重要です。つまり、sys.frame(i)$ofileが存在する最大のiです。

_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
    }
}
_
0
Aaron McDaid