如何在Rmarkdown中实现bash变量跨不同代码块的持久化传递
解决方案
默认情况下R Markdown的每个bash代码块都会启动独立的shell子进程,执行完成后进程销毁,因此环境变量无法在多个代码块之间直接共享。你可以通过以下几种方案实现shell变量/会话的持久化:
方案1:临时文件中转变量(最常用,配置简单)
通过给所有bash代码块自动添加前后缀代码,实现运行前加载之前保存的变量、运行后存储当前变量到临时文件,达到变量共享的效果。
完整示例代码如下:
--- title: "Test" output: pdf_document: toc: true highlight: zenburn html_document: toc: true theme: united --- ```{r setup, include=FALSE} # 生成临时文件存储bash变量,文档渲染完成后自动删除 bash_env_tmp <- tempfile(fileext = ".sh") # 全局钩子:给所有bash块自动加变量加载、保存逻辑 knitr::opts_hooks$set(bash = function(options) { options$code <- c( # 运行代码前加载之前存储的变量 sprintf("source %s 2>/dev/null", bash_env_tmp), options$code, # 运行代码后保存当前所有变量到临时文件 sprintf("declare -p > %s 2>/dev/null", bash_env_tmp) ) return(options) })
正文内容
TEST="12345" echo $TEST
其他正文内容
echo $TEST
渲染后第二个bash块会正常输出`12345`。如果不需要保存所有变量,只需要把最后一行的`declare -p`改成`declare -p 变量名1 变量名2`,仅导出指定变量即可。 ## 方案2:R环境变量中转(适合变量少的场景) 所有代码块启动的子进程都会继承R进程的环境变量,你可以将需要共享的变量存入R的环境变量,后续bash块可以直接读取:
配置钩子捕获导出的变量
knitr::knit_hooks$set(output = function(x, options) { if (options$engine == "bash") { lines <- strsplit(x, "\n")[[1]] # 识别导出标记行,导入R环境 export_lines <- grep("^##R_EXPORT ", lines, value = TRUE) for (line in export_lines) { var_def <- sub("^##R_EXPORT ", "", line) eval(parse(text = paste0("Sys.setenv(", var_def, ")"))) } # 输出中去掉导出标记行 x <- paste(grep("^##R_EXPORT ", lines, invert = TRUE, value = TRUE), collapse = "\n") } return(x) })
第一个bash块
TEST="12345" echo $TEST # 输出标记行,后续钩子会识别该行导入R环境 echo "##R_EXPORT TEST=$TEST"
第二个bash块
echo $TEST
## 方案3:共用常驻shell会话(需要完整会话共享时使用) 如果需要共享整个shell会话的状态(包括工作目录、别名、后台进程等),可以借助`tmux`在后台维持一个常驻shell会话,所有bash代码块的代码都发送到该会话执行,实现完整的会话共享。 内容的提问来源于stack exchange,提问作者LEo
相关产品推荐
相关产品推荐

