我想了解下面的 for 循环并可能简化它。例如,我想连接目录中每个示例的 rem 文件。
文件:
file1.1.fq
file1.rem.1.fq
file1.2.fq
file1.rem.2.fq
file2.1.fq
file2.rem.1.fq
file2.2.fq
file2.rem.2.fq
for循环:
list=`for i in *rem*.1.fq; do echo $i | cut -f 1 -d \.; done`
for i in $list; do cat $i.rem.1.fq $i.rem.2.fq > $i.rem.b.fq; done
我可以在不列清单的情况下执行此操作吗?其作用是什么cut -f 1 -d
?如果文件名的部分位于列表中的两者之间,为什么可以cat $i.rem.1.fq
工作但不能?这是否意味着它捕获了之前的所有内容(例如 file1)?cat $i.1.fq
rem
*
*rem*
答案1
尝试:
for i in *.rem.1.fq; do
cat -- "$i" "${i%.1.fq}.2.fq" > "${i%.1.fq}.b.fq"
done
也许添加对文件是否存在的检查:
for i in *.rem.1.fq; do
if [ -e "${i%.1.fq}.2.fq" ] && [ ! -e "${i%.1.fq}.b.fq" ]; then
cat -- "$i" "${i%.1.fq}.2.fq" > "${i%.1.fq}.b.fq"
fi
done
问题中提出的方法很容易出错 - 如果文件包含空格,第二个for
循环可能无法正常运行。
cut -f 1 -d.
将字符串切割成字段(在本例中由 分隔.
),并输出请求的字段(在本例中,仅输出第一个字段)。如果给定字符串file 1.whatever
,它将输出file 1
。同样,鉴于 glob 模式*rem*.1.fq
可能返回带有anyremthing.1.fq
–*
通配符匹配的文件名,这很容易出错任何事物(包括没有什么)。
更好的选择是执行单个循环并使用参数扩展,并在循环内进行某种形式的替换以匹配具有相关名称的其他文件。
- 上面使用了 glob 模式
*.rem.1.fq
- 您可能希望进一步缩小范围 - 例如。file[0-9].rem.1.fq
。 ${param%string}
用于循环中删除后缀.1.fq
.许多 shell 还支持其他形式的参数扩展替换 - 例如。${param/string/repl}
。
此外,引用 all"$param"
或"$(command)"
替换通常是一个好主意 - 否则大多数 shell 将应用字段分割和文件名生成,并且您可能最终会尝试而cat file 1
不是cat 'file 1'
,例如。
如果--
您不能保证文件名不会以-
.