你有么有遇到过以下情况:
1 写的脚本忘记保存,然后苦逼地再写一遍
2 脚本不小心或者小心地删掉了,但后来又发现很有用,依然苦逼地再写一遍
3 实验室的服务器炸了,写的脚本全没了
一般情况下,第三种情况不会遇到,但前两种你肯定遇到过,当然你很少写脚本除外。
如果遇到过前两种情况,脚本的本地备份是不错选择
原理
- 利用 scp 实现远端和本地之间的文件传输
- 在服务器中获取需要备份的文件目录,并保存为log文件
- 在本地使用scp获取这个log文件,有了这个文件,本地就知道需要备份哪些服务器的文件至本地了
- 分别将获取log文件的脚本(位于服务器上)和执行备份的脚本(位于本地windows)的脚本设置定期执行(并且是有序的执行,因为要先有log文件再进行备份),这样就实现了定期备份脚本的功能
- 备份的文件夹用当日日期来命名,如果你备份周期比较短,可能会用到时分秒来命名了
代码实现
scp 的用法请参考:scp实现服务器和本地文件的传输
1 获取需要备份的文件目录
该脚本位于服务器
cat Backup_scripts.R
library("optparse")
option_list = list(make_option(c("-f", "--folder"), type = "character", default = NULL, help = "Folder to be backup"))
args <- parse_args(OptionParser(option_list=option_list))
if(is.null(args$folder))
args$folder = "/sibcb2/bioinformatics2/wangjiahao"
setwd(args$folder)
cat("Collecting file path ...\n")
Folders = list.files(args$folder)
xFolders = Folders[Folders != "software"]
patterns = c("\\.R$", "\\.py$", "\\.sh$", "\\.wdl$")
getFile <- function(folder){
res = sapply(patterns, function(x) list.files(folder, x, recursive = TRUE))
return(paste0(folder, "/", as.character(unlist(res))))
}
files = as.character(unlist(sapply(xFolders, getFile)))
date = gsub("-", "_", Sys.Date())
out = paste0("/sibcb2/bioinformatics2/wangjiahao/code/Backup/", date, ".txt")
write.table(files, file = out, sep = "\n", quote = FALSE, col.names = FALSE, row.names = FALSE)
cat("Done!\n")
- 用法
由于脚本里面指定了默认的需要备份的路径,所以可以直接运行。如果需要备份其他目录(例如 xxxx),直接在命令上加个参数就行了:
Rscript Backup_scripts.R --folder xxxx
倒数第三行的out变量是log文件的保存位置,需要自行修改,懒得写成参数传递的形式了
- 生成的log文件:
head 2020_12_10.txt & wc -l 2020_12_10.txt
288 2020_12_10.txt
code/CommonData/Build_ENSG.R
code/function/buildTabix.R
code/function/fmrNormalization.R
code/function/Oncotator_FG.R
code/function/PathwayEnrichment.R
code/function/workflow.R
code/myscript/Backup_scripts.R
code/myscript/copy_script_v1.R
code/myscript/copy_script_v2.R
code/myscript/copy_script_v3.R
本地获取log文件,并执行备份
该脚本位于本地
cat Backup_scripts.R
setwd("G:/Methylation/Backup")
userName = "wangjiahao"
serverIP = "xx.xx.x.xx"
date = gsub("-", "_", Sys.Date())
masterFolder = paste0(getwd(), "/", date)
outFolder = paste0(masterFolder, "/", userName)
suppressWarnings(dir.create(masterFolder))
suppressWarnings(dir.create(outFolder))
remoteLogFile = paste0("/sibcb2/bioinformatics2/wangjiahao/code/Backup/", gsub("-","_",Sys.Date()), ".txt")
cmd = paste0("scp ", userName, "@", serverIP, ":", remoteLogFile, " ", masterFolder)
system(cmd)
logFiles = readLines(paste0(masterFolder, "/", date, ".txt"))
remoteFiles = paste0("/sibcb2/bioinformatics2/wangjiahao/", logFiles)
for(i in 1:length(remoteFiles)){
remoteFile = remoteFiles[i]
localFolder = paste0(outFolder, "/", dirname(logFiles[i]))
suppressWarnings(dir.create(localFolder, recursive = TRUE))
cmd = paste0("scp ", userName, "@", serverIP, ":", remoteFile, " ", localFolder)
system(cmd)
}
其中,用户名和服务器IP需要自定义
使用过程:
G:\Script\CMD>Rscript G:/Script/R/Backup_script.R
2020_12_10.txt 100% 10KB 2.0MB/s 00:00
[1] 0
Build_ENSG.R 100% 394 55.3KB/s 00:00
buildTabix.R 100% 961 235.9KB/s 00:00
fmrNormalization.R 100% 889 174.2KB/s 00:00
Oncotator_FG.R 100% 13KB 1.7MB/s 00:00
PathwayEnrichment.R 100% 27KB 2.7MB/s 00:00
workflow.R 100% 2118 518.4KB/s 00:00
Backup_scripts.R 100% 933 228.4KB/s 00:00
copy_script_v1.R 100% 2478 127.7KB/s 00:00
copy_script_v2.R 100% 2466 65.3KB/s 00:00
copy_script_v3.R 100% 1258 32.3KB/s 00:00
....
我不插网线传输速度也可以达到几M/s,每个脚本啪的一下就传好了,很快啊
接下来实现自动备份!
定时任务设置
需要同时设置本地和远程端的定时任务
1 本地设置
windows 定时任务
2 远程端设置
Linux - 定时任务
在搜索目录的时候,一定要把软件安装目录给去掉,因为里面有很深的目录和很多的不是自己的脚本,检索会消耗很多时间,例如conda的目录。
真的挺实用的~
2021-06-08
后来想到更简单且高效的方法:
终端服务器可以选择每一小时或两小时生成一个日志文件,因此日志文件命名时要加上小时的单位(R语言:strsplit(gsub("[ -]", "_", Sys.time()), ":")[[1]][1]
)。
此外,还有一个问题,频繁的备份会产生很多日期相同小时不同的日志文件,那么本地应该如何选择备份哪一个呢?当然,我们应该备份最近生成的那个日志文件对应的脚本,但是本地电脑是不知道终端最近备份的是哪个日志文件的。解决办法也很简单,同样的原理:在终端每次备份时把备份的日期及小时保存在另外一个文件里,这个文件的名字是可以唯一的,因为它的内容每次都会被覆盖更新。这样,我们在本地首先获取这个包含最近备份时间的日志文件内容,又因为最近备份时间也是包含待备份脚本路径的日志文件的命名规则,因此,根据这个时间,我们可以准确获取最近生成的那个文件路径日志文件并进行下一步的备份。
之所以说更简单高效,是因为之前是在电脑每次开机时自动备份一次,后来想想这并不是最好的备份方法。现在我改进了备份方法:因为之所以需要备份是因为你想避免你打开了终端软件(我使用的是Moba Xterm)连接服务器后对文件造成不可挽回的修改,因此在打开Moba的时候进行备份显然是更有效的。实现这个想法也不难,就是在打开Moba的同时进行服务器文件备份,同样是使用windows的cmd功能:
start D:\MobaXterm\MobaXterm_Personal_20.6.exe & Rscript G:/Script/R/Backup_script.R
命名为start_Moba.cmd
,可以直接单击这个文件就可以同时实现打开Moba和文件备份, 为了更方便,可以将这个文件固定到任务栏或 Windows 自定义cmd命令。
这样只会在打开Moba时才会进行备份,而不是每次开机时都要弹出备份的窗口,是不是前者更简单高效呢~