Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
261 views
in Technique[技术] by (71.8m points)

bash - How to know the path to an R file inside it when it is sourced?

When I source a file in R, I want to know inside it what its path is. Is there a way to do so in R?

source("somefile.R")

See BASH_SOURCE (I just need ${BASH_SOURCE[0]} though) for a similar feature in bash.

https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html

EDIT: The following solution does not work as expected. See f() being called outside main1.R.

$ cat main1.R 

f = function() {
if (!is.null(src <- Sys.getenv("R_SOURCE")) && nzchar(src)) {
    cat("my name is '", src, "'
", sep = "")
}
}

f() 
$ Rscript main.R 
R> source2 <- function(path, ...) {
+   path <- normalizePath(path)
+   oldsrc <- Sys.getenv("R_SOURCE")
+   on.exit({ Sys.setenv(R_SOURCE = oldsrc) }, add = TRUE)
+   Sys.setenv(R_SOURCE = path)
+   source(path, ...)
+ }
R> 
R> source2('main1.R')
my name is '/private/tmp/y/main1.R'
R> f()
R> 

In bash, no matter where the function is called, it always knows where it is defined.

$ cat ./main1.sh 
#!/usr/bin/env bash
# vim: set noexpandtab tabstop=2:

function f {
  declare -p BASH_SOURCE
}
$ cat ./main.sh 
#!/usr/bin/env bash
# vim: set noexpandtab tabstop=2:

source main1.sh
set -v
declare -p BASH_SOURCE
f

$ ./main.sh 
declare -p BASH_SOURCE
declare -a BASH_SOURCE=([0]="./main.sh")
f
declare -a BASH_SOURCE=([0]="main1.sh" [1]="./main.sh")

EDIT:

The following solution based on getSrcFilename() does not work when one wants to access the path within the file run by Rscript.

$ cat f.R 
f=function() {
  getSrcFilename(f)
}

(function() {
  print(getSrcFilename(f))
})()
$ Rscript f.R
R> f=function() {
+   getSrcFilename(f)
+ }
R> 
R> (function() {
+   print(getSrcFilename(f))
+ })()
character(0)
R> 
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you think the solution given doesn't work, then presumably you don't just want to know the path when you source the file, but permanently for any objects it creates.

The srcref system provides at least some of what you want, if options(keep.source=TRUE)

Eg:

> source("~/Downloads/main.R")
> getSrcFilename(svy_vglm,full.names=TRUE)
[1] "svgam.R"
> getSrcFilename(f)
[1] "main.R"
> getSrcDirectory(f)
[1] "/Users/tlum005/Downloads"

The directory is the directory by which the file was looked up: if you just did source("main.R"), the directory would be . rather than its absolute form.

Rewriting your main.R you might get

f = function() {

   cat(getSrcDirectory(f))

}

f()

Two weaknesses here are that srcref attributes are copied by assignment and f() relies on knowing its own name. If you did

g<-f
g()
rm(f)
g()

you might want the two calls to g() to both return errors (since g() wasn't sourced) or both to return the directory, but you wouldn't want one of each. This can be worked around in this case with sys.function(): if main.R is

f = function() {

   cat(getSrcDirectory(sys.function()))

}

f()

the assignment works

> source("~/Downloads/main.R")
/Users/tlum005/Downloads
> f()
/Users/tlum005/Downloads
> g<-f
> g()
/Users/tlum005/Downloads
> rm(f)
> g()
/Users/tlum005/Downloads

I wouldn't advocate using this method -- I can't think of a situation where you wouldn't be better off just putting the source code somewhere better organised -- but I think it does answer the question.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...