for循环简化

for循环简化

我想了解下面的 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.fqrem**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',例如。

如果--您不能保证文件名不会以-.

相关内容