Programing

실행 스크립트의 경로 결정

lottogame 2020. 4. 17. 08:10
반응형

실행 스크립트의 경로 결정


같은 디렉토리에있는 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)

현재 스크립트 파일의 경로를 반환합니다. 스크립트가 저장된 후에 작동합니다.


commandArgs함수를 사용하여 Rscript가 전달한 모든 옵션을 실제 R 인터프리터로 가져 와서 검색 할 수 --file=있습니다. 스크립트가 경로에서 시작되었거나 전체 경로로 시작된 경우 script.name아래는로 시작됩니다 '/'. 그렇지 않으면,에 상대적이어야하며 cwd전체 경로를 얻기 위해 두 경로를 연결할 수 있습니다.

편집 :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)

other.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 콘솔에서 '소스'할 때 Suppressingfire의 솔루션을 작동시킬 수 없었습니다.
Rscript를 사용할 때 hadley의 솔루션을 사용할 수 없었습니다.

두 세계의 최고?

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)]])

내가 잊어 버렸기 때문에 어떻게 작동하는지 묻지 마십시오.


R 스크립트의 경로얻는 것으로 부터 rakensi 의 대답은 가장 정확하고 정말 훌륭한 IMHO입니다. 그러나 여전히 더미 기능을 통합 한 핵입니다. 다른 사람들이 쉽게 찾을 수 있도록 여기에 인용하고 있습니다.

sourceDir <-getSrcDirectory (함수 (더미) {더미})

이것은 명령문이 배치 된 파일의 디렉토리를 제공합니다 (더미 함수가 정의 된 위치). 그런 다음 작업 direcory를 설정하고 상대 경로를 사용하는 데 사용할 수 있습니다.

setwd(sourceDir)
source("other.R")

또는 절대 경로를 만들려면

 source(paste(sourceDir, "/other.R", sep=""))

이것은 나를 위해 작동

library(rstudioapi)    
rstudioapi::getActiveDocumentContext()$path

Supressingfire의 답변이 축소 된 변형 :

source_local <- function(fname){
    argv <- commandArgs(trailingOnly = FALSE)
    base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
    source(paste(base_dir, fname, sep="/"))
}

하나의 모든 것! (-RStudio 콘솔을 처리하도록 2019 년 1 월 1 일 업데이트 됨)

#' 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)
                }
            }
        }
    }
}

이것은 나를 위해 작동합니다. 명령 행 인수에서이를 제거하고, 원치 않는 텍스트를 제거하고, dirname을 수행 한 후 마지막으로 전체 경로를 가져옵니다.

args <- commandArgs(trailingOnly = F)  
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))

이 질문에 대한 답변을 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 실행 파일을 통해 호출 할 때 스크립트의 올바른 전체 경로를 반환 하는 함수 를 제공 합니다.


방금 직접 해결했습니다. 스크립트의 이식성을 보장하려면 항상 다음으로 시작하십시오.

wd <- setwd(".")
setwd(wd)

"."때문에 작동합니다. 유닉스 명령 $ PWD와 같이 번역합니다. 이 문자열을 문자 객체에 할당하면 해당 문자 객체를 setwd ()에 삽입 할 수 있으며, Presto 코드는 기계의 위치 나 파일 구조의 위치에 관계없이 항상 현재 디렉토리를 작업 디렉토리로 실행합니다. 위치. (추가 보너스 : wd 객체는 file.path () (예 : file.path (wd, "output_directory")와 함께 사용하여 명명 된 디렉토리로 이어지는 파일 경로에 관계없이 표준 출력 디렉토리를 만들 수 있습니다. 이를 위해서는이 방법으로 참조하기 전에 새 디렉토리를 만들어야하지만 wd 객체로도 도움이 될 수 있습니다.

또는 다음 코드는 똑같은 작업을 수행합니다.

wd <- getwd()
setwd(wd)

또는 객체에 파일 경로가 필요하지 않은 경우 간단히 다음을 수행 할 수 있습니다.

setwd(".")

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)

getopt 패키지는 get_Rscript_filename여기에 제시된 것과 동일한 솔루션을 사용하지만 표준 R 모듈로 이미 작성된 기능을 제공하므로 "스크립트 경로 가져 오기"기능을 복사하여 모든 스크립트에 붙여 넣을 필요는 없습니다. 당신은 쓰기.


참조 findSourceTraceback()R.utils의 , 포장하는

모든 호출 프레임에서 source ()에 의해 생성 된 모든 'srcfile'객체를 찾습니다. 이를 통해 source ()가 현재 어떤 파일을 스크립팅했는지 확인할 수 있습니다.


내 스크립트가 심볼릭 링크 디렉토리에서 작동 할 때 위의 구현에 문제가 있거나 적어도 위의 솔루션이 효과가 없다고 생각합니다. @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))
  }
})()

당신이 단순히 사용할 수있는 경우의 99 % :

sys.calls()[[1]] [[2]]

스크립트가 첫 번째 인수가 아닌 미친 전화에는 작동하지 않습니다 source(some args, file="myscript"). 이 멋진 경우에는 @hadley를 사용하십시오.


#!/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='/'))

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 블록을 확장 할 수 있습니다.


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 이름을 분리하십시오.

splitstr <- rev(strsplit(thisscript, "\\/")[[1]])
otherscript <- paste0(paste(rev(splitstr[2:length(splitstr)]),collapse="/"),"/other.R")

스크립트가 아닌 foo.R경로 위치를 알고 있다면, 모든 source공통 경로 를 항상 참조하도록 코드를 변경할 수 있다면 root다음과 같은 도움이 될 것입니다.

주어진

  • /app/deeply/nested/foo.R
  • /app/other.R

이 작동합니다

#!/usr/bin/env Rscript
library(here)
source(here("other.R"))

프로젝트 루트를 정의하는 방법 https://rprojroot.r-lib.org/참조 하십시오 .


호출 스택을 보면 실행중인 각 스크립트의 파일 경로를 얻을 수 있습니다. 가장 유용한 두 가지는 아마도 현재 실행중인 스크립트이거나 소스가 될 첫 번째 스크립트 일 것입니다 (입력).

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) ))()

참고 URL : https://stackoverflow.com/questions/1815606/determine-path-of-the-executing-script

반응형