我有以下格式的文件名,我想根据子字符串匹配(Orange,Apple)和常量(S4,S5)对文件进行分类,
文件名示例_S6_trimmed_, _S8_trimmed_, _S9_trimmed_, _S10_trimmed_
Orange1_S4_trimmed_1.fastq
Orange1_S4_trimmed_2.fastq
Orange2_S4_trimmed_1.fastq
Orange2_S4_trimmed_2.fastq
Apple1_S4_trimmed_1.fastq
Apple1_S4_trimmed_2.fastq
Apple2_S4_trimmed_1.fastq
Apple2_S4_trimmed_2.fastq
Orange1_S5_trimmed_1.fastq
Orange1_S5_trimmed_2.fastq
Orange2_S5_trimmed_1.fastq
Orange2_S5_trimmed_2.fastq
Apple1_S5_trimmed_1.fastq
Apple1_S5_trimmed_2.fastq
Apple2_S5_trimmed_1.fastq
Apple2_S5_trimmed_2.fastq
我想要做的是对几个样本 S4、S5 重复相同的操作……
cat Orange*_S4_trimmed_1.fastq >Orange_S4_trimmed_1.fastq
cat Orange*_S4_trimmed_2.fastq >Orange_S4_trimmed_2.fastq
cat Apple*_S4_trimmed_1.fastq >Apple_S4_trimmed_1.fastq
cat Apple*_S4_trimmed_2.fastq >Apple_S4_trimmed_2.fastq
这是我在 bash 中编写的脚本,
#!/bin/bash
filename="samples.txt"
while read -r sample;
do
echo $sample
cat ${sample}_trimmed_1.fastq >${sample}_trimmed_1.fastq
cat ${sample}_trimmed_2.fastq >${sample}_trimmed_2.fastq
done <$filename
这是我的 samples.txt 文件的格式,
samples.txt
Apple*_S4
Apple*_S5
Orange*_S4
Orange*_S5
有没有更好的方法对一大组文件执行此操作?提前感谢您的帮助。
我目前正在根据 Bodo 上的评论制定解决方案,
#!/bin/bash
for file in *1_*_trimmed_1.fastq;
do
echo $file
subs=`echo $file | cut -d_ -f1 | tr -d 0-9`
echo $subs
sample=`echo $file | cut -d_ -f2`
echo $sample
cat ${subs}*_${sample}_trimmed_1.fastq >${subs}_${sample}_trimmed_1.fastq
cat ${subs}*_${sample}_trimmed_2.fastq >${subs}_${sample}_trimmed_2.fastq
done
答案1
1. 将所有源文件粘贴到目标位置
正如您的问题所示,示例代码将文件集的所有文件粘贴到其目标文件中:
#!/bin/sh
destination=""
# Select all source files, but not any existing the destination files:
for file in *[0-9]*_S[0-9]*_trimmed_*[0-9].fastq
do
if [ "${destination}" != "${file%%[0-9]*}_${file#*_}" ]
then
# Switch to next file set:
destination="${file%%[0-9]*}_${file#*_}"
echo "${destination}"
fi
# Copy the current source file to destination
cat "${file}" >"${destination}"
done
这几乎只适用于命名管道作为目标文件,将接收到的数据传输到其他地方。
2. 仅将最后一个源文件粘贴到其目标位置
如果目标是一个常规文件,那么将所有源文件写入目标将是一个巨大的开销,因为内容每次都会被覆盖,只留下最新版本继续保留。
第二种解决方案可避免开销并最大程度地减少要写入的数据量:
#!/bin/sh
destination=""
source=""
# Select all source files, but not any existing the destination files:
for file in *[0-9]*_S[0-9]*_trimmed_*[0-9].fastq
do
if [ "${destination}" != "${file%%[0-9]*}_${file#*_}" ]
then
if [ "${destination}" != "" ]
then
# Not the start situation. Write last file of file set to the destination file:
cat "${source}" >"${destination}"
fi
# Switch to next file set:
destination="${file%%[0-9]*}_${file#*_}"
echo ${destination}
fi
# Store the current source file name for the next cycle
source=${file}
done
# Write last source file of the last file set to the destination, if it exists:
if [ "${destination}" != "" ]
then
cat "${source}" >"${destination}"
fi
正如你用于cat
文件复制一样,我也使用了它。但通常人们会改用cp
。因此,人们会将行替换cat "${file}" >"${destination}"
为
cp "${file}" "${destination}"
如果源文件或目标文件不再需要编辑,则应考虑创建硬链接。这样就不会出现数据重复(目标文件不会占用额外的磁盘空间)。只会创建目标文件名,指向与所选源文件相同的数据区域(inode):
cp -l --remove-destination "${file}" "${destination}"
对于大型文件(例如视频数据)来说,这将大大加快速度。