简单重命名
Linux下文件重命名可以通过两个命令完成,mv和rename。
- mv: 直接运行可以进行单个文件的重命名,如 mv old_name.txt new_name.txt
- rename: 默认支持单个文件或有固定规律的一组文件的批量重命名,示例如下。
rename演示
使用touch新建文件,两个样品(分别是易生信a,易生信b),各自双端测序得到的FASTQ文件。
ysx@ehbio:~/test$ touch YSX_a_1.fq.gz YSX_a_2.fq.gz YSX_b_2.fq.gz YSX_b_1.fq.gz ysx@ehbio:~/test$ ls YSX_a_1.fq.gz YSX_a_2.fq.gz YSX_b_1.fq.gz YSX_b_2.fq.gz
把文件名中的易生信(YSX)改为易汉博 (ehbio):
# rename '被替换文字' '要替换成的文字' 操作对象 ysx@ehbio:~/test$ rename 'YSX' 'ehbio' *.gz ysx@ehbio:~/test$ ls ehbio_a_1.fq.gz ehbio_a_2.fq.gz ehbio_b_1.fq.gz ehbio_b_2.fq.gz
不同操作系统,rename的使用方法略有不同。印象中:
在CentOS都是上面的语法 rename old new file_list
在Ubuntu都是下面的语法 rename s/old/new/ file_list
# 在CentOS下,该命令未起作用 ysx@ehbio:~/test$ rename 's/ehbio_//' * ysx@ehbio:~/test$ ls ehbio_a_1.fq.gz ehbio_a_2.fq.gz ehbio_b_1.fq.gz ehbio_b_2.fq.gz # 如果写的rename命令没发挥作用,使用man rename查看其具体使用方法, 个人经验,无外乎上面提到的两种用法。 ysx@ehbio:~/test$ man rename # NAME # rename - rename files # # SYNOPSIS # rename [options] expression replacement file...
替换后缀:
# 替换后缀 ysx@ehbio:~/test$ rename 'fq' 'fastq' *.gz ysx@ehbio:~/test$ ls ehbio_a_1.fastq.gz ehbio_a_2.fastq.gz ehbio_b_1.fastq.gz ehbio_b_2.fastq.gz
复杂重命名
但有时,需要重命名的文件不像上面那样有很清晰的模式,直接可以替换,需要多几步处理获得对应关系。
假如已经有对应关系
如下name.map.txt是自己手动编写的文件,a对应Control, b对应Treatment。
ysx@ehbio:~/test$ ls name.map.txt ehbio_a_1.fastq.gz ehbio_a_2.fastq.gz ehbio_b_1.fastq.gz ehbio_b_2.fastq.gz ysx@ehbio:~/test$ cat name.map.txt a Control b Treatment
组合文件名,使用mv重命名
首先组合出原名字和最终名字:
ysx@ehbio:~/test$ awk '{print "ehbio_"$1"_1.fastq.gz", "ehbio_"$2"_1.fastq.gz", "ehbio_"$1"_2.fastq.gz", "ehbio_"$2"_2.fastq.gz"}' name.map.txt ehbio_a_1.fastq.gz ehbio_Control_1.fastq.gz ehbio_a_2.fastq.gz ehbio_Control_2.fastq.gz ehbio_b_1.fastq.gz ehbio_Treatment_1.fastq.gz ehbio_b_2.fastq.gz ehbio_Treatment_2.fastq.gz
加上mv:
ysx@ehbio:~/test$ awk '{print "mv ehbio_"$1"_1.fastq.gz ehbio_"$2"_1.fastq.gz"; print "mv ehbio_"$1"_2.fastq.gz ehbio_"$2"_2.fastq.gz";}' name.map.txt mv ehbio_a_1.fastq.gz ehbio_Control_1.fastq.gz mv ehbio_a_2.fastq.gz ehbio_Control_2.fastq.gz mv ehbio_b_1.fastq.gz ehbio_Treatment_1.fastq.gz mv ehbio_b_2.fastq.gz ehbio_Treatment_2.fastq.gz
可以直接拷贝上面的输出再粘贴运行,或存储为文件运行:
ysx@ehbio:~/test$ awk '{print "mv ehbio_"$1"_1.fastq.gz ehbio_"$2"_1.fastq.gz"; print "mv ehbio_"$1"_2.fastq.gz ehbio_"$2"_2.fastq.gz";}' name.map.txt >rename.sh ysx@ehbio:~/test$ #bash rename.sh
也可以把print改为system直接运行:
ysx@ehbio:~/test$ ls ehbio_a_1.fastq.gz ehbio_a_2.fastq.gz ehbio_b_1.fastq.gz ehbio_b_2.fastq.gz name.map.txt rename.sh ysx@ehbio:~/test$ awk '{system("mv ehbio_"$1"_1.fastq.gz ehbio_"$2"_1.fastq.gz"); system("mv ehbio_"$1"_2.fastq.gz ehbio_"$2"_2.fastq.gz");}' name.map.txt ysx@ehbio:~/test$ ls ehbio_Control_1.fastq.gz ehbio_Control_2.fastq.gz ehbio_Treatment_1.fastq.gz ehbio_Treatment_2.fastq.gz name.map.txt rename.sh
使用rename会不会稍微简单一点?
一定注意符号匹配和避免误匹配。
# 注意引号和空格 ysx@ehbio:~/test$ awk '{print("rename "$1" "$2" *.fastq.gz"); }' name.map.txt rename a Control *.fastq.gz rename b Treatment *.fastq.gz # 上面的命令有什么问题吗? # fastq中也存在a,是否也会被替换 # ehbio中也存在b,是否也会倍替换 ysx@ehbio:~/test$ awk '{system("rename "$1" "$2" *.fastq.gz"); }' name.map.txt # 执行后,文件名都乱套了 ysx@ehbio:~/test$ ls ehbio_b_1.fControlstq.gz ehbio_b_2.fControlstq.gz ehTreatmentio_Control_1.fastq.gz ehTreatmentio_Control_2.fastq.gz name.map.txt rename.sh # 再重命名回去,再次尝试 ysx@ehbio:~/test$ rename 'Control' 'a' * ysx@ehbio:~/test$ rename 'Treatment' 'b' * ysx@ehbio:~/test$ ls ehbio_a_1.fastq.gz ehbio_a_2.fastq.gz ehbio_b_1.fastq.gz ehbio_b_2.fastq.gz name.map.txt rename.sh # 重命名两侧加下划线, 这也是我们做匹配时常需要注意的,尽量限制让匹配更准确 ysx@ehbio:~/test$ awk '{system("rename _"$1"_ _"$2"_ *.fastq.gz"); }' name.map.txt # 打印出来看下 ysx@ehbio:~/test$ awk '{print("rename _"$1"_ _"$2"_ *.fastq.gz"); }' name.map.txt # rename _a_ _Control_ *.fastq.gz # rename _b_ _Treatment_ *.fastq.gz
从原文件名获取对应关系
基于paste
像上面自己写好对应文件是一个方法,有时也可以从文件名推测规律,生成对应文件。
如下有一堆测序原始数据,选择A组样品来查看:
# 如下有一堆测序原始数据,选择A组样品来查看 ysx@ehbio:~/test2# ls A* A1_FRAS192317015-1a_1.fq.gz A2_FRAS192320421-1a_1.fq.gz A3_FRAS192317017-1a_1.fq.gz A1_FRAS192317015-1a_2.fq.gz A2_FRAS192320421-1a_2.fq.gz A3_FRAS192317017-1a_2.fq.gz
中间的那一串字符FRA...-是我们不需要的。
观察规律,先按下划线将文件名分割(_),再获取第1,3个元素;另外习惯性给生物重复前面也加上下划线(用到了sed的记忆匹配)。
ysx@ehbio:~/test2# ls A*.gz | cut -f 1,3 -d '_' | sed 's/\([A-E]\)/\1_/' A_1_1.fq.gz A_1_2.fq.gz A_2_1.fq.gz A_2_2.fq.gz
把原样品名字与新样品名字对应起来,这里用到了paste和输入重定向 (<):
ysx@ehbio:~/test2# paste <(ls A*.gz) <(ls A*.gz | cut -f 1,3 -d '_' | sed 's/\([A-E]\)/\1_/') A1_FRAS192317015-1a_1.fq.gz A_1_1_fq.gz A1_FRAS192317015-1a_2.fq.gz A_1_2_fq.gz A2_FRAS192320421-1a_1.fq.gz A_2_1_fq.gz A2_FRAS192320421-1a_2.fq.gz A_2_2_fq.gz A3_FRAS192317017-1a_1.fq.gz A_3_1_fq.gz A3_FRAS192317017-1a_2.fq.gz A_3_2_fq.gz
把原样品名字与新样品名字对应起来,这里用到了paste和输入重定向 (<):
ysx@ehbio:~/test2# paste <(ls A*.gz) <(ls A*.gz | cut -f 1,3 -d '_' | sed 's/\([A-E]\)/\1_/') | sed 's#^#/bin/mv #' /bin/mv A1_FRAS192317015-1a_1.fq.gz A_1_1_fq.gz /bin/mv A1_FRAS192317015-1a_2.fq.gz A_1_2_fq.gz /bin/mv A2_FRAS192320421-1a_1.fq.gz A_2_1_fq.gz /bin/mv A2_FRAS192320421-1a_2.fq.gz A_2_2_fq.gz /bin/mv A3_FRAS192317017-1a_1.fq.gz A_3_1_fq.gz /bin/mv A3_FRAS192317017-1a_2.fq.gz A_3_2_fq.gz
软链接也是常用的 (但一定注意源文件使用全路径):
ysx@ehbio:~/test2# paste <(ls *.gz) <(ls *.gz | sed 's/\./_/' | cut -f 1,3,4 -d '_' | sed 's/\([A-E]\)/analysis\/\1_/') | sed 's#^#ln -s `pwd`/#' ln -s `pwd`/A1_FRAS192317015-1a_1.fq.gz analysis/A_1_1_fq.gz ln -s `pwd`/A1_FRAS192317015-1a_2.fq.gz analysis/A_1_2_fq.gz ln -s `pwd`/A2_FRAS192320421-1a_1.fq.gz analysis/A_2_1_fq.gz . . . ln -s `pwd`/E15_FRAS192317028-1a_1.fq.gz analysis/E_15_1_fq.gz ln -s `pwd`/E15_FRAS192317028-1a_2.fq.gz analysis/E_15_2_fq.gz
基于awk
转换下输入数据的格式,字符处理在awk也可以操作,但我更习惯使用命令组合,每一步都用最简单的操作,不容易出错。
ysx@ehbio:~/test2# ls A*.gz | sed -e 's/\([A-E]\)/\1_/' A_1_FRAS192317015-1a_1.fq.gz A_1_FRAS192317015-1a_2.fq.gz A_2_FRAS192320421-1a_1.fq.gz A_2_FRAS192320421-1a_2.fq.gz A_3_FRAS192317017-1a_1.fq.gz A_3_FRAS192317017-1a_2.fq.gz ysx@ehbio:~/test2# ls A*.gz | sed -e 's/\([A-E]\)/\1_/' -e 's/\./_./' A_1_FRAS192317015-1a_1_.fq.gz A_1_FRAS192317015-1a_2_.fq.gz A_2_FRAS192320421-1a_1_.fq.gz A_2_FRAS192320421-1a_2_.fq.gz A_3_FRAS192317017-1a_1_.fq.gz A_3_FRAS192317017-1a_2_.fq.gz
采用awk生成对应关系:
# 生成样品重复,计数出错了,每行记了一个数,而实际两行是一个样本。 ysx@ehbio:~/test2# ls A*.gz | sed -e 's/\([A-E]\)/\1_/' -e 's/\./_./' | awk 'BEGIN{OFS=" ";FS="_"}{sum[$1]+=1; print $0, $1"_"sum[$1]"_"$4$5;}' A_1_FRAS192317015-1a_1_.fq.gz A_1_1.fq.gz A_1_FRAS192317015-1a_2_.fq.gz A_2_2.fq.gz A_2_FRAS192320421-1a_1_.fq.gz A_3_1.fq.gz A_2_FRAS192320421-1a_2_.fq.gz A_4_2.fq.gz A_3_FRAS192317017-1a_1_.fq.gz A_5_1.fq.gz A_3_FRAS192317017-1a_2_.fq.gz A_6_2.fq.gz
# 稍微改进下 ysx@ehbio:~/test2# ls A*.gz | sed -e 's/\([A-E]\)/\1_/' -e 's/\./_./' | awk 'BEGIN{OFS=" ";FS="_"}{sum[$1]+=1; print $0, $1"_"sum[$1]"_"$4$5;}' A_1_FRAS192317015-1a_1.fq.gz A_1_1.fq.gz A_1_FRAS192317015-1a_2.fq.gz A_2_2.fq.gz A_2_FRAS192320421-1a_1.fq.gz A_3_1.fq.gz A_2_FRAS192320421-1a_2.fq.gz A_4_2.fq.gz A_3_FRAS192317017-1a_1.fq.gz A_5_1.fq.gz A_3_FRAS192317017-1a_2.fq.gz A_6_2.fq.gz # 记得源文件名字的替换 ysx@ehbio:~/test2# ls A*.gz | sed -e 's/\([A-E]\)/\1_/' -e 's/\./_./' | awk 'BEGIN{OFS=" ";FS="_"}{sum[$1]+=1; print $0, $1"_"sum[$1]"_"$4$5;}' | sed -e 's/_//' -e 's/_\././' -e 's#^#ln -s `pwd`/#' |head ln -s `pwd`/A1_FRAS192317015-1a_1.fq.gz A_1_1.fq.gz ln -s `pwd`/A1_FRAS192317015-1a_2.fq.gz A_2_2.fq.gz
好了,重命名就到这了。有了这个思路,关键是如何根据自己的文件名字特征,构造对应的匹配关系。
另外,Window下使用Git for windows应该也可以实现对应的操作。