在shell中直接调用使用R
前言:这篇博客的内容其实是在我另外一篇博客《python、R、shell兼容》之前就整理好的,见
https://blog.csdn.net/weixin_62528784/article/details/148149416?spm=1001.2014.3001.5502,
问题是放得太久了,暂时想不起来要往下写什么了,但是也整理得差不多了,就作为后者的一个补充。
我们先以1个简单的例子来来切入
——查看帮助文档:
虽然在jupyter notebook的cell或者vscode的httpgd中都能够快速查看帮助文档,类似于Rstudio的并行界面;
但是一个函数帮助文档太长的时候,我们想看某个参数的细节就像大海捞针一样,非常的浪费时间;
如果能够用上shell的grep/awk/sed快速文本处理命令,那么这些细节上就能够快速的处理,
但是我们不打开radian或者R terminal,
我们只想在shell中展示,这样才方便利用shell强大的文本处理工具:
比如说我手头上有一段简短的代码
coef.months <- c(coef(mod.lm2)[2:12],-sum(coef(mod.lm2)[2:12]))plot(coef.months, xlab = "Month", ylab = "Coefficient",xaxt = "n", col = "blue", pch = 19, type = "o")
axis(side = 1, at = 1:12, labels = c("J", "F", "M", "A","M", "J", "J", "A", "S", "O", "N", "D"))
其实就是绘制一个最小二乘法拟合之后的回归模型的系数曲线,
我在绘制简单的线图的时候不想使用原本的x轴标度,而是自定义,
假设我突然忘了plot函数中xaxt参数的用法,但是我又不想从头打开文档去找,哪怕文档只有100多行,我就想在shell中快速查找,使用grep命令。
下面这条命令想必大家都很熟悉,就是在shell中执行R命令的格式:
Rscript -e 'R command'R -e 'R command'# 示例
Rscript -e 'help("plot")' | grep -i -C 5 "xaxt"
grep能用的花样就很多了:
比如说-i忽略大小写,-C查看上下文,这样我就知道xaxt是禁用自带轴标度了
所以在shell中直接使用R命令的方式(不考虑进入R terminal,也不考虑R内核的其他实现方式)
一,Rscript命令模式(或R命令模式)
1,linux下直接执行R命令
Rscript -e 'R command'
R -e 'R command'
简单的例子:
2,linux下执行R脚本(或静默执行R脚本)
R --no-save < terminalR.R
R --no-save -q < terminalR.R
R --no-save --slave < terminalR.R
举个简单的例子:比如说是hello world
总之<符号是必须的:
但是这里还是要注意一下Rscript和R命令的区别:
二,R script 脚本化(便于直接在shell脚本中和python程序、shell命令行等并行、串行、联动)
脚本化是一种对用户友好的封装,不仅能提高程序的健壮性,还能很容易的集成到分析流程中。
——》统一推荐使用Rscript命令行
1,R 脚本简介 Rscript
脚本化,就是把程序写成有输入和输出的独立程序文件。就像shell的 ls 命令, 比对软件 STAR 一样,用户只需要调用脚本名字、给出参数,程序就能判断参数是否合法,并返回结果。把程序像黑盒一样封装起来,方便用户使用,还能轻易整合到 snakemake 等流程中。
推荐使用朴素的写法,尽量只使用R核心API,依赖越少越稳定,以便其他用户复用。
推荐格式如下:# 比如说一个以使用monocle2包的脚本为例- 脚本名字以 xx.script.R 结尾。
- 开头部分写上脚本的目的,使用方法,测试环境,版本变化
- R脚本模板 # Aim: do monocle2 as a script, output to a dir
# how to use: $ Rscript this.script.R xx.Seurat.obj [outputRoot]
# Env: R 4.1.0
# version: 0.2-20240504
# version: 0.3-20240504 set parameters
2,R 脚本化相关技术
脚本内部把参数列表保存在数组 myArgs=commandArgs(TRUE) 中,下标0是该脚本文件名本身,下标1是第一个参数,以此类推。
获取的参数是字符串形式,要做算术运算需要主动转为数字形式,比如 as.numeric(str2)。
一般还需要验证参数,比如个数、类型是否正确,输出文件是否已经存在等。
(1)接收参数
# 实例(Ubuntu 24.04 + R 4.4.2)
#例1: 接收参数,并对第2个参数加100后输出
$ cat test1.R # 先写好vim
#获取命令行参数
myArgs = commandArgs(TRUE)#myArgs是所有参数的向量
print(myArgs)
print(class(myArgs))
message("length:", length(myArgs), ", first:", myArgs[1] )n1=as.numeric(myArgs[2])
print( n1+100 )
然后下面就是试验了:运行该脚本,并传入参数
如果传入参数个数不够,不报错,但是会计算异常,比如第二个转为数字返回NA。
总结就是:
通过 Rscript 执行R脚本。R脚本内通过 arr = commandArgs(TRUE) 接收参数,接收到的是一个数组,第一个参数的下标是1;类型为字符串,可以按需要强转。
(2)参数校验与主动报错
先检查参数个数,再检查参数类型,还要检查输出文件是否存在,如果存在是否覆盖?
主动报错,即在参数不合法时,主动抛出错误,终止程序运行,并给出错误提示或给出合理化建议。
①如果参数个数不对,则报错:
只有一个参数的时候报错了,参数长度不符合:
两个参数就正常执行了:
②如果输入(file)文件不存在,则报错
该脚本同时获取数据文件的行列数
我们先写入一个经典的base中就有的数据看看
在shell中是输出成功的,能打开该文件:
有文件时,返回行列数
我们查看一下确实没问题
没有文件时,主动报错
③如果输出(dir)文件夹不存在,则报错
测试:第二个参数是输出文件夹,不存在则报错
④stopifnot(): 脚本参数的校验,和函数参数的校验类似
# stopifnot(): If any of the expressions (in ... or exprs) are not all TRUE,
# stop is called, producing an error message indicating the first expression which was not (all) true.
测试1: 参数个数至少2个
测试2: 参数个数不够2个则报错
(3)打印时间戳进度条
运行时间长的脚本需要进度条,以缓解用户的焦虑,告诉用户程序运行到哪了,方便用户估计还要等多久。一般有伴随着进度条直接写时分秒的,还有写已经运行时间的。
①显示时分秒的
for(i in 1:10){Sys.sleep(runif(1)*0.5+0.5)message("[",Sys.time(), "]", i)
}
②其他时间相关函数:
# 查询时区
> Sys.time() #现在的时间 [1] "2025-03-16 23:14:12 CST"
> Sys.timezone() #查看当前时区 [1] "Asia/Shanghai"# 支持的时区
> OlsonNames() #所有R支持的时区
> grep("Shanghai", OlsonNames(), value=T)
#[1] "Asia/Shanghai"# 设置时区后,服务器R时间就和本地一致了
> Sys.setenv(TZ = "Asia/Shanghai")
> Sys.timezone() # 查看时区 "Asia/Shanghai"> Sys.time() #现在的时间和windows右下角一致了
# [1]"2025-03-16 23:15:49 CST"
参考:
https://www.cnblogs.com/emanlee/p/13900239.html
https://www.biomooc.com/R/R-script.html