使用 R 包安装可执行脚本
Installing executable scripts with R package
在大多数脚本语言(例如 Ruby、Python 等)中,包管理器(例如 gem、pip 等)可以将脚本安装为可执行文件,并且 link 它们到 PATH 变量中引用的目录(例如 /usr/local/bin)。这会将那些可执行脚本变成 shell 命令,用户可以 运行 以独立的方式在编程界面之外执行这些命令。
不知R中是否也有这种可能。鉴于 R 使用标准 Makefile,我想一定有办法做到这一点,尽管是非标准的。我已经知道我们可以在 R 脚本 using the docopt
package 中读取命令行参数。但是有没有办法在安装包时将脚本安装为可执行文件?
如果能在这个主题上发挥主导作用就好了,但是来自 CRAN 的一个工作示例也足够了。
简短(而且非常悲伤)的回答:你不能。但请继续阅读。
推理:R 只会将包内容写入其自己的 .libPaths()
目录(或第一个目录,以防给出多个),或用户指定的目录。
所以,说 /usr/local/bin/
简直遥不可及。这是一种防御策略。
这也很可悲——我写 littler (also CRAN page) 正是为了这个目的:可执行的 R 脚本。我们有 数十名 的工作人员从 cron
工作中调用。那么我们该怎么办? 一次性 soft-link 来自包含脚本的包的 scripts/
子目录到 /usr/local/bin
。在软件包升级时,link 作为软 link.
持续存在
这也是我为 所做的,例如 所有 examples shipping with littler and more from other packages. Many of them use docopt。
我有类似的目标,这是我确定的解决方案。我在我的 R 包中添加了一个函数,它通过并(详细地)创建了从 ~/.local/bin
到我的包 exec
文件夹中的每个脚本的符号链接。
其他合理的默认位置可能是 ~/.local/lib/R/bin
或 ~/bin
,但我最喜欢 ~/.local/bin
。
所以在安装包后,我将用户引导至 运行
Rscript -e 'mypackage::install_executable_scripts()'
#' @export
install_executable_scripts <- function(into = "~/.local/bin", overwrite = FALSE) {
scripts <- dir(system.file("exec", package = "mypackage"),
full.names = TRUE)
if (!dir.exists(into)) dir.create(into)
into <- normalizePath(into)
dests <- file.path(normalizePath(into), basename(scripts))
if (any(already_exist <- file.exists(dests))) {
if (overwrite) {
to_del <- dests[already_exist]
cli::cat_bullet("Deleting existing file: ", to_del,
bullet_col = "red")
unlink(to_del)
} else {
cli::cat_bullet(sprintf(
"Skipping script '%s' because a file by that name already exists at the destination",
basename(scripts[already_exist])))
scripts <- scripts[!already_exist]
dests <- dests[!already_exist]
}
}
if (length(scripts)) {
file.symlink(scripts, dests)
cli::cat_line("Created symlinks:")
cli::cat_bullet(dests, " ->\n ", scripts, bullet_col = "green")
} else
cli::cat_line("Nothing installed")
PATHS <- normalizePath(strsplit(Sys.getenv("PATH"), ":", fixed = TRUE)[[1]],
mustWork = FALSE)
if(!into %in% PATHS)
warning(sprintf("destination '%s' is not on the PATH", into))
}
在大多数脚本语言(例如 Ruby、Python 等)中,包管理器(例如 gem、pip 等)可以将脚本安装为可执行文件,并且 link 它们到 PATH 变量中引用的目录(例如 /usr/local/bin)。这会将那些可执行脚本变成 shell 命令,用户可以 运行 以独立的方式在编程界面之外执行这些命令。
不知R中是否也有这种可能。鉴于 R 使用标准 Makefile,我想一定有办法做到这一点,尽管是非标准的。我已经知道我们可以在 R 脚本 using the docopt
package 中读取命令行参数。但是有没有办法在安装包时将脚本安装为可执行文件?
如果能在这个主题上发挥主导作用就好了,但是来自 CRAN 的一个工作示例也足够了。
简短(而且非常悲伤)的回答:你不能。但请继续阅读。
推理:R 只会将包内容写入其自己的 .libPaths()
目录(或第一个目录,以防给出多个),或用户指定的目录。
所以,说 /usr/local/bin/
简直遥不可及。这是一种防御策略。
这也很可悲——我写 littler (also CRAN page) 正是为了这个目的:可执行的 R 脚本。我们有 数十名 的工作人员从 cron
工作中调用。那么我们该怎么办? 一次性 soft-link 来自包含脚本的包的 scripts/
子目录到 /usr/local/bin
。在软件包升级时,link 作为软 link.
这也是我为 所做的,例如 所有 examples shipping with littler and more from other packages. Many of them use docopt。
我有类似的目标,这是我确定的解决方案。我在我的 R 包中添加了一个函数,它通过并(详细地)创建了从 ~/.local/bin
到我的包 exec
文件夹中的每个脚本的符号链接。
其他合理的默认位置可能是 ~/.local/lib/R/bin
或 ~/bin
,但我最喜欢 ~/.local/bin
。
所以在安装包后,我将用户引导至 运行
Rscript -e 'mypackage::install_executable_scripts()'
#' @export
install_executable_scripts <- function(into = "~/.local/bin", overwrite = FALSE) {
scripts <- dir(system.file("exec", package = "mypackage"),
full.names = TRUE)
if (!dir.exists(into)) dir.create(into)
into <- normalizePath(into)
dests <- file.path(normalizePath(into), basename(scripts))
if (any(already_exist <- file.exists(dests))) {
if (overwrite) {
to_del <- dests[already_exist]
cli::cat_bullet("Deleting existing file: ", to_del,
bullet_col = "red")
unlink(to_del)
} else {
cli::cat_bullet(sprintf(
"Skipping script '%s' because a file by that name already exists at the destination",
basename(scripts[already_exist])))
scripts <- scripts[!already_exist]
dests <- dests[!already_exist]
}
}
if (length(scripts)) {
file.symlink(scripts, dests)
cli::cat_line("Created symlinks:")
cli::cat_bullet(dests, " ->\n ", scripts, bullet_col = "green")
} else
cli::cat_line("Nothing installed")
PATHS <- normalizePath(strsplit(Sys.getenv("PATH"), ":", fixed = TRUE)[[1]],
mustWork = FALSE)
if(!into %in% PATHS)
warning(sprintf("destination '%s' is not on the PATH", into))
}