确定执行脚本的路径
我有一个名为 foo.R
的脚本,其中包含另一个脚本 other.R
,它位于同一目录中:
#!/usr/bin/env Rscript
message("Hello")
source("other.R")
但我希望 R
找到other.R
无论当前工作目录是什么。
换句话说,foo.R
需要知道它自己的路径。我怎样才能做到这一点?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
这里有一个简单的解决方案。该命令:
返回当前脚本文件的路径。保存脚本后即可运行。
Here there is a simple solution for the problem. This command:
returns the path of the current script file. It works after the script was saved.
您可以使用
commandArgs
函数获取 Rscript 传递给实际 R 解释器的所有选项,并在其中搜索--file=
。如果您的脚本是从路径启动的,或者是使用完整路径启动的,则下面的script.name
将以'/'
开头。否则,它必须相对于cwd
,并且您可以连接两个路径以获得完整路径。编辑:听起来您只需要上面的
script.name
并删除路径的最终组成部分。我删除了不需要的cwd()
示例并清理了主脚本并发布了我的other.R
。只需将此脚本和 other.R 脚本保存到同一目录中,chmod +x
它们,然后运行主脚本即可。main.R:
other.R:
输出:
这就是我相信德曼正在寻找的东西。
You can use the
commandArgs
function to get all the options that were passed by Rscript to the actual R interpreter and search them for--file=
. If your script was launched from the path or if it was launched with a full path, thescript.name
below will start with a'/'
. Otherwise, it must be relative to thecwd
and you can concat the two paths to get the full path.Edit: it sounds like you'd only need the
script.name
above and to strip off the final component of the path. I've removed the unneededcwd()
sample and cleaned up the main script and posted myother.R
. Just save off this script and theother.R
script into the same directory,chmod +x
them, and run the main script.main.R:
other.R:
output:
This is what I believe dehmann is looking for.
从 R 控制台“获取”时,我无法使 Suppressingfire 的解决方案发挥作用。
使用 Rscript 时,我无法使 hadley 的解决方案起作用。
两全其美?
I couldn't get Suppressingfire's solution to work when 'source'ing from the R console.
I couldn't get hadley's solution to work when using Rscript.
Best of both worlds?
不要问我它是如何工作的,因为我已经忘记了:/
Don't ask me how it works though, because I've forgotten :/
这对我有用
This works for me
rakensi 来自 获取 R 脚本的路径 是最正确且非常出色的恕我直言。然而,它仍然是一个包含虚拟函数的 hack。我把它引用在这里,是为了让其他人更容易找到。
这给出了放置语句的文件目录(定义虚拟函数的位置)。然后它可以用于设置工作目录并使用相对路径,例如
或创建绝对路径
The answer of rakensi from Getting path of an R script is the most correct and really brilliant IMHO. Yet, it's still a hack incorporating a dummy function. I'm quoting it here, in order to have it easier found by others.
This gives the directory of the file where the statement was placed (where the dummy function is defined). It can then be used to set the working direcory and use relative paths e.g.
or to create absolute paths
我为此制作了一个包,可在 CRAN 和 GitHub 上获取,名为 this.path。当前版本是2.5.0 (2024-06-29),您可以在这里找到它:
https://CRAN.R-project.org/package=this.path
https://github.com/ArcadeAntics/this.path
从 CRAN 安装:
或从 GitHub 安装开发版本:
然后通过以下方式使用它:
或:
下面的答案是我原来的答案,仅供参考,尽管它的功能比上面可用的最新版本要少得多。改进包括:
与以下 GUI 的兼容性:
Windows 上的“Rgui”
后台作业位于 ' RStudio'
'VSCode' + 'REditorSupport'
'Jupyter'
'Emacs' + 'ESS'
与以下函数和包的兼容性:
编译器::loadcmp()
utils::Sweave()
box::use()
knitr::knit()
plumber::plumb()
shiny::runApp()
package:targets
testthat::source_file()
处理文件名在类 Unix 下从 shell 运行 R 脚本时带有空格
处理从 shell 运行 R 脚本的两种用途(
-f
FILE
和 <代码>--file=FILE)正确规范化路径当使用带有参数的
source()
时(chdir = TRUE)
使用
处理
例如file://
URL >source()source("file:///path/to/file")
和source("file:///C:/path/to /文件”)
改进了对
source()
中连接而不是字符串的处理< /p>对
source()
中 URL 路径名的处理,例如:如果在文件中使用
this.path()
,它将返回“https://host/path/to/file”
。这也适用于以"http://"
、"ftp://"
和"ftps://"
开头的 URL。作为示例,请尝试:引入函数
here()
//this.proj()
,类似于here::here(),用于指定相对于执行脚本的目录的绝对文件路径//执行脚本的项目根目录将规范化路径保存在其中第一次在脚本中调用
this.path()
时会使用适当的环境,从而可以更快地在同一脚本中使用后续时间,并且独立于工作目录。这意味着setwd()
将不再破坏this.path()
(只要setwd()
使用 AFTER< /em> 在该脚本中第一次调用this.path()
)原始答案:
我的答案是对 Jerry T 的回答。我发现的问题是,他们通过检查是否在堆栈的第一帧中找到变量
ofile
来猜测是否进行了source()
调用。这不适用于嵌套源调用,也不适用于从非全局环境进行的源调用。另外,顺序是错误的。我们必须在检查 shell 参数之前查找源调用。这是我的解决方案:I've made a package for this, available on CRAN and GitHub, called this.path. The current version is 2.5.0 (2024-06-29), you can find it here:
https://CRAN.R-project.org/package=this.path
https://github.com/ArcadeAntics/this.path
Install it from CRAN:
or install the development version from GitHub:
and then use it by:
or:
The answer below is my original answer, kept just for reference, though it is quite a bit less functional than the most recent versions available above. Improvements include:
compatibility with the following GUIs:
'Rgui' on Windows
background jobs in 'RStudio'
'VSCode' + 'REditorSupport'
'Jupyter'
'Emacs' + 'ESS'
compatibility with the following functions and packages:
compiler::loadcmp()
utils::Sweave()
box::use()
knitr::knit()
plumber::plumb()
shiny::runApp()
package:targets
testthat::source_file()
handling filenames with spaces when running an R script from a shell under Unix-alikes
handling both uses of running an R script from a shell (
-f
FILE
and--file=FILE
)correctly normalizes the path when using
source()
with argument(chdir = TRUE)
handling of
file://
URLs withsource()
such assource("file:///path/to/file")
andsource("file:///C:/path/to/file")
improved handling of a connection instead of a character string within
source()
handling of URL pathnames in
source()
, such as:if
this.path()
was used within the file, it would return"https://host/path/to/file"
. This also works for URLs starting with"http://"
,"ftp://"
, and"ftps://"
. As an example, try:introduces functions
here()
/ /this.proj()
, similar to here::here(), for specifying absolute file paths relative to the executing script's directory / / executing script's project rootsaving the normalized path within its appropriate environment the first time
this.path()
is called within a script, making it faster to use subsequent times within the same script and being independent of working directory. This means thatsetwd()
will no longer breakthis.path()
(as long assetwd()
is used AFTER the first call tothis.path()
within that script)Original Answer:
My answer is an improvement upon Jerry T's answer. The issue I found is that they are guessing whether a
source()
call was made by checking if variableofile
is found in the first frame on the stack. This will not work with nested source calls, nor source calls made from a non-global environment. Additionally, the order is wrong. We must look for source call BEFORE checking the shell arguments. Here is my solution:我的全合一! (--01/09/2019 更新以处理 RStudio 控制台)
My all in one! (--01/09/2019 updated to deal with RStudio Console)
Supressingfire 答案的简化版本:
A slimmed down variant of Supressingfire's answer:
这对我有用。只需将其从命令行参数中删除,去掉不需要的文本,执行目录名,最后从中获取完整路径:
This works for me. Just greps it out of the command line arguments, strips off the unwanted text, does a dirname and finally gets the full path from that:
我已将这个问题的答案总结并扩展为 rprojroot。也适用于使用
knitr
进行编织。I have wrapped up and extended the answers to this question into a new function
thisfile()
in rprojroot. Also works for knitting withknitr
.我尝试了这个问题的几乎所有内容,获取 R 脚本的路径, 获取当前脚本的路径< /a>, 查找当前 .R 文件的位置 和 R 命令用于将工作目录设置为 Rstudio 中的源文件位置,但最后发现自己手动浏览 CRAN 表并发现
scriptName
库,提供
current_filename()
函数,该函数返回脚本的正确完整路径在 RStudio 中采购以及通过 R 或 RScript 可执行文件调用时。I tried almost everything from this question, Getting path of an R script, Get the path of current script, Find location of current .R file and R command for setting working directory to source file location in Rstudio, but at the end found myself manually browsing the CRAN table and found
scriptName
librarywhich provides
current_filename()
function, which returns proper full path of the script when sourcing in RStudio and also when invoking via R or RScript executable.我喜欢 steamer25 的解决方案,因为它似乎最适合我的目的。但是,在 RStudio(在 Windows 中)中调试时,路径将无法正确设置。原因是,如果在 RStudio 中设置断点,则获取文件会使用备用“调试源”命令,该命令设置的脚本路径略有不同。这是我当前使用的最终版本,它在调试时解释了 RStudio 中的这种替代行为:
I liked steamer25's solution as it seems the most robust for my purposes. However, when debugging in RStudio (in windows), the path would not get set properly. The reason being that if a breakpoint is set in RStudio, sourcing the file uses an alternate "debug source" command which sets the script path a little differently. Here is the final version which I am currently using which accounts for this alternate behavior within RStudio when debugging:
我也遇到了这个问题,以上解决方案都不适合我。也许有源代码或类似的东西,但还不够清楚。
我发现这个对我来说很优雅的解决方案:
其中重要的是
fileSnapshot()
,它为您提供了有关文件的大量信息。它返回一个包含 8 个元素的列表。当您选择path
作为列表元素时,路径将返回,并以\\
作为分隔符,因此其余代码只是更改它。我希望这有帮助。
I also had this problem, and none of the above solutions worked for me. Maybe with the
source
or things like that, but it was not clear enough.I found this, for me elegant, solution:
The important thing in that is the
fileSnapshot()
that gives you a lot of information about a file. It returns a list of 8 elements. When you pickpath
as the list element, the path is returned with\\
as separator, so the rest of the code is just to change that.I hope this helps.
我刚刚自己解决了这个问题。为了确保脚本的可移植性,请始终以以下内容开头:
它之所以有效,是因为“.”翻译起来就像 Unix 命令 $PWD。将此字符串分配给字符对象允许您将该字符对象插入到 setwd() 中,并且您的代码将始终以其当前目录作为工作目录运行,无论它在谁的计算机上或它在文件结构中的位置。 (额外的好处:wd 对象可以与 file.path() (即 file.path(wd, "output_directory")一起使用,以允许创建标准输出目录,而不管通向指定目录的文件路径如何。这确实要求您在以这种方式引用它之前创建新目录,但这也可以通过 wd 对象来辅助。
或者,以下代码执行完全相同的操作:
或者,如果您不需要 in 中的文件路径。一个对象,你可以简单地:
I just worked this out myself. To ensure portability of your script always begin it with:
It works because "." translates like the Unix command $PWD. Assigning this string to a character object allows you to then insert that character object into setwd() and Presto your code will always run with its current directory as the working directory, no matter whose machine it is on or where in the file structure it is located. (Extra bonus: The wd object can be used with file.path() (ie. file.path(wd, "output_directory") to allow for the creation of a standard output directory regardless of the file path leading to your named directory. This does require you to make the new directory before referencing it this way but that, too, can be aided with the wd object.
Alternately, the following code performs the exact same thing:
or, if you don't need the file path in an object you can simply:
您可以将 r 脚本包装在 bash 脚本中,并将脚本的路径作为 bash 变量检索,如下所示:
You can wrap the r script in a bash script and retrieve the script's path as a bash variable like so:
我喜欢这种方法:
I like this approach:
请注意,getopt 包提供了 get_Rscript_filename 函数,该函数仅使用此处提供的相同解决方案,但已在标准 R 模块中为您编写,因此您无需复制并粘贴“将脚本路径”函数添加到您编写的每个脚本中。
Note that the getopt package provides the
get_Rscript_filename
function, which just uses the same solution presented here, but is already written for you in a standard R module, so you don't have to copy and paste the "get script path" function into every script you write.Steamer25 的方法有效,但前提是路径中没有空格。在 macOS 上,至少
cmdArgs[match]
返回类似于/base/some~+~dir~+~with~+~whitespace/
的内容/base/一些\ dir\ 与\ 空白/
。我通过在返回之前用一个简单的空格替换“~+~”来解决这个问题。
显然你仍然可以像 aprstar 那样扩展 else 块。
Steamer25's approach works, but only if there is no whitespace in the path. On macOS at least the
cmdArgs[match]
returns something like/base/some~+~dir~+~with~+~whitespace/
for/base/some\ dir\ with\ whitespace/
.I worked around this by replacing the "~+~" with a simple whitespace before returning it.
Obviously you can still extend the else block like aprstar did.
如果不是脚本,
foo.R
,知道它的路径位置,如果您可以更改代码以始终引用来自公共根的所有
那么这些可能会有很大的帮助:源
路径给定
/app/deeply/nested/foo .R
/app/other.R
这将起作用
请参阅https: //rprojroot.r-lib.org/ 了解如何定义项目根。
If rather than the script,
foo.R
, knowing its path location, if you can change your code to always reference allsource
'd paths from a commonroot
then these may be a great help:Given
/app/deeply/nested/foo.R
/app/other.R
This will work
See https://rprojroot.r-lib.org/ for how to define project roots.
我在上面的实现中遇到了问题,因为我的脚本是从符号链接目录操作的,或者至少这就是为什么我认为上述解决方案对我不起作用。按照 @ennukiller 的回答,我将 Rscript 包装在 bash 中。我使用 pwd -P 设置路径变量,它解析符号链接的目录结构。然后将路径传递到 Rscript 中。
Bash.sh
foo.R
I had issues with the implementations above as my script is operated from a symlinked directory, or at least that's why I think the above solutions didn't work for me. Along the lines of @ennuikiller's answer, I wrapped my Rscript in bash. I set the path variable using
pwd -P
, which resolves symlinked directory structures. Then pass the path into the Rscript.Bash.sh
foo.R
我会使用 @steamer25 方法的变体。重点是,即使我的会话是通过 Rscript 启动的,我也更喜欢获取最后的源脚本。以下代码片段包含在文件中时,将提供一个变量
thisScript
,其中包含脚本的规范化路径。我承认(滥用)使用了 source'ing,所以有时我会调用 Rscript,并且
--file
参数中提供的脚本会获取另一个脚本,该脚本又会获取另一个脚本......有一天我会投资制作我的乱码变成了一个包。I would use a variant of @steamer25 's approach. The point is that I prefer to obtain the last sourced script even when my session was started through Rscript. The following snippet, when included on a file, will provided a variable
thisScript
containing the normalized path of the script.I confess the (ab)use of source'ing, so sometimes I invoke Rscript and the script provided in the
--file
argument sources another script that sources another one... Someday I will invest in making my messy code turns into a package.99% 的情况您可能会简单地使用:
它不适用于脚本不是第一个参数的疯狂调用,即
source(some args, file="myscript")
。在这些奇特的情况下使用@hadley's。99% of the cases you might simply use:
It will not work for crazy calls where the script is not the first argument, i.e.,
source(some args, file="myscript")
. Use @hadley's in these fancy cases.通过查看调用堆栈,我们可以获得正在执行的每个脚本的文件路径,最有用的两个脚本可能是当前正在执行的脚本,或者是要获取的第一个脚本(条目)。
By looking at the call stack we can get the filepath of each script being executed, the two most useful will probably either be the currently executing script, or the first script to be sourced (entry).
我发现的最灵活的解决方案是利用 rstudioapi::getSourceEditorContext() 和(可选)
sub()
请尝试以下操作:
rstudioapi::getSourceEditorContext()$path
返回当前文件的完整路径sub(".*/ ", "", .)
提取最后一个/
之后的所有内容,仅保留文件名。我希望这有帮助!
The most flexible solution to this that I have found utilizes
rstudioapi::getSourceEditorContext()
and (optionally)sub()
Try the following:
The
rstudioapi::getSourceEditorContext()$path
returns the full path of the current fileThe
sub(".*/", "", .)
extracts everything after the last/
, leaving only the name of the file.I hope that helps!
请参阅 R.utilsfindSourceTraceback() > 包,其中
See
findSourceTraceback()
of the R.utils package, which令人惊奇的是,R 中没有“$0”类型结构!您可以通过对用 R 编写的 bash 脚本进行 system() 调用来完成此操作:
然后只需将 scriptpath.sh 名称拆分为 other.R
Amazing there is no '$0' type structure in R! You can do it with a system() call to a bash script written in R:
Then just split out the scriptpath.sh name for other.R
我在 HPC 集群环境中工作。我在与生产运行不同的位置开发代码。在开发过程中,我通常从命令行以交互方式调用 R(不使用 RStudio)。有很多
source("foo.R")
正在进行。在生产运行期间,我通常编写一个 bash 脚本来尝试不同的参数并在单独的目录中运行每组参数。 bash 脚本利用工作负载管理器(即 SLURM)。在这种环境下,设置环境变量是微不足道的。考虑到这一点,以下解决方案最适合我。
other.R
foo.R
如果从 R 交互式 shell 并在
/path/to/R/code
中运行它,只需执行If running不是从交互式 shell 运行,也不是从
/path/to/R/code
运行,请先设置环境变量R_SRC
,然后调用Rscript
I work in an HPC cluster environment. I develop my code in a different location from where I do my production runs. During development, I'm usually calling R interactively from the command line (not using RStudio). There is lots of
source("foo.R")
going on.During production runs, I usually write a bash script that tries different parameters and runs each set of parameters in a separate directory. The bash script utilizes the workload manager (i.e. SLURM). In this environment, it is trivial to set an environmental variable. With this in mind, the below solution works best for me.
other.R
foo.R
If running this from the R interactive shell and within
/path/to/R/code
, simply doIf running not from the interactive shell and not running from
/path/to/R/code
, set the environmental variableR_SRC
first, then callRscript
解决方案于 2016 年问世。非常感谢作者 Sahil Seth!
CRAN 上的包
funr
并且 github 提供了获取完整路径的函数sys.script()
到当前脚本。它甚至引用了类似的SO post。因此,解决方案是:
myscript.R:
然后
在命令行执行命令: 将输出,eg:
到控制台。
The solution arrived in 2016. Many thanks to the author, Sahil Seth!
The package
funr
on CRAN and github provides the functionsys.script()
which gets the full path to the current script. It even references a similar SO post.Thus, the solution is:
myscript.R:
and then executing the command:
at the command line will output, e.g.:
to the console.