【问题标题】:Running zcat on multiple files using a for loop使用 for 循环在多个文件上运行 zcat
【发布时间】:2014-10-14 01:15:27
【问题描述】:

我对终端/bash 很陌生,也许以前有人问过这个问题,但我找不到我要找的东西,也许是因为我不确定要搜索什么来回答我的问题.

我正在尝试格式化一些文件以进行基因分析,虽然我可以为每个样本文件编写以下命令,但我知道有更好的方法:

zcat myfile.fastq.gz | awk 'NR % 8 == 5 || NR % 8 == 6 || NR % 8 == 7 || NR % 8 == 0 {print $0}' | gzip > myfile.2.fastq.gz
zcat myfile.fastq.gz | awk 'NR % 8 == 1 || NR % 8 == 2 || NR % 8 == 3 || NR % 8 == 4 {print $0}' | gzip > myfile.1.fastq.gz

我有以下文件:

-bash-3.2$ ls
BB001.fastq BB013.fastq.gz  IN014.fastq.gz  RV006.fastq.gz  SL083.fastq.gz
BB001.fastq.gz  BB014.fastq.gz  INA01.fastq.gz  RV007.fastq.gz  SL192.fastq.gz
BB003.fastq.gz  BB015.fastq.gz  INA02.fastq.gz  RV008.fastq.gz  SL218.fastq.gz
BB004.fastq.gz  IN001.fastq.gz  INA03.fastq.gz  RV009.fastq.gz  SL276.fastq.gz
BB006.fastq.gz  IN002.fastq.gz  INA04.fastq.gz  RV010.fastq.gz  SL277.fastq.gz
BB008.fastq.gz  IN007.fastq.gz  INA05.fastq.gz  RV011.fastq.gz  SL326.fastq.gz
BB009.fastq.gz  IN010.fastq.gz  INA1M.fastq.gz  RV012.fastq.gz  SL392.fastq.gz
BB010.fastq.gz  IN011.fastq.gz  RV003.fastq.gz  SL075.fastq.gz  SL393.fastq.gz
BB011.fastq.gz  IN012.fastq.gz  RV004.fastq.gz  SL080.fastq.gz  SL395.fastq.gz
BB012.fastq.gz  IN013.fastq.gz  RV005.fastq.gz  SL081.fastq.gz

我想将两个 zcat 函数应用于每个文件,从每个文件创建两个新文件,而不用写出 50 次。我在 R 中使用了很多 for 循环,但不知道在 bash 中从哪里开始。我可以用语言说出我想要的,希望有人可以帮我编写代码!:

for FILENAME.fastq.gz in all files in cd

zcat FILENAME.fastq.gz | awk 'NR % 8 == 5 || NR % 8 == 6 || NR % 8 == 7 || NR % 8 == 0 {print $0}' | gzip > FILENAME.2.fastq.gz
zcat FILENAME.fastq.gz | awk 'NR % 8 == 1 || NR % 8 == 2 || NR % 8 == 3 || NR % 8 == 4 {print $0}' | gzip > FILENAME.1.fastq.gz

非常感谢您的帮助!

*****编辑*****

我的符号有点不对劲,这是最后一个正确的 for 循环:

for fname in *.fastq.gz
do
    gzcat "$fname" | awk 'NR % 8 == 5 || NR % 8 == 6 || NR % 8 == 7 || NR % 8 == 0 {print $0}' | gzip >../../SeparateReads/"${fname%.fastq.gz}.2.fastq.gz"
    gzcat "$fname" | awk 'NR % 8 == 1 || NR % 8 == 2 || NR % 8 == 3 || NR % 8 == 4 {print $0}' | gzip >../../SeparateReads/"${fname%.fastq.gz}.1.fastq.gz"
done

*****后续问题*****

当我运行以下命令时:

for fname in *.1.fastq.gz
do
cat ./CleanedSeparate/XhoI/"$fname" ./CleanedSeparate/MseI/"${fname%.1.fastq.gz}.2.fastq.gz" > ./FinalCleaned/"${fname%.1.fastq.gz}.fastq.gz"
done

我收到此错误:

cat: ./CleanedSeparate/XhoI/*.1.fastq.gz: No such file or directory
cat: ./CleanedSeparate/MseI/*.2.fastq.gz: No such file or directory

显然我没有正确使用 *。关于我哪里出错的任何提示?

【问题讨论】:

  • 该错误基本上意味着您在当前目录中没有与通配符*.1.fastq.gz匹配的文件。在这种情况下,shell 在静态字符串上“循环”(您可以更改它,但无论如何这不是您想要的)。如果匹配此通配符的文件在其他地方,则需要包含路径。也许您正在寻找for fname in CleanedSeparate/XhoI/*.1.fast.gz 并在稍后的代码中进行相应的重构以使其适应这种变化?

标签: bash for-loop terminal filenames


【解决方案1】:
for fname in *.fastq.gz
do
    zcat "$fname" | awk 'NR % 8 == 5 || NR % 8 == 6 || NR % 8 == 7 || NR % 8 == 0 {print $0}' | gzip >"${fname%.fastq.gz}.2.fastq.gz"
    zcat "$fname" | awk 'NR % 8 == 1 || NR % 8 == 2 || NR % 8 == 3 || NR % 8 == 4 {print $0}' | gzip >"${fname%.fastq.gz}.1.fastq.gz"
done

关键点:

  • for fname in *.fastq.gz

    这将遍历当前目录中以.fastq.gz 结尾的每个文件。如果文件位于不同的目录中,则使用:

    for fname in /path/to/*.fastq.gz
    

    /path/to/ 是获取这些文件的路径。

  • zcat "$fname"

    这部分很简单。它将文件名替换为zcat 的参数。

  • "${fname%.fastq.gz}.1.fastq.gz"

    这有点棘手。要获得所需的输出文件名,我们需要将.1 插入到原始文件名中。在bash 中执行此操作的最简单方法是从带有${fname%.fastq.gz} 的文件名中删除.fastq.gz 后缀,其中% 是bash-speak 的意思,即删除后面的内容。然后,我们添加新的后缀.1.fastq.gz,我们就有了正确的文件名。

在不同的目录中创建新文件

根据后续问题,这不起作用:

for fname in *.1.fastq.gz
do
    cat ./CleanedSeparate/XhoI/"$fname" ./CleanedSeparate/MseI/"${fname%.1.fastq.gz}.2.fastq.gz" > ./FinalCleaned/"${fname%.1.fastq.gz}.fastq.gz"
done

问题在于,在for 语句中,shell 正在当前目录中寻找*.1.fastq.gz。但是,他们不在那里。他们在./CleanedSeparate/XhoI/。相反,运行:

dir1=./CleanedSeparate/XhoI
for fname in "$dir1"/*.1.fastq.gz
do
    base=${fname#$dir1/}
    base=${base%.1.fastq.gz}
    echo "base=$base"
    cat "$fname" "./CleanedSeparate/MseI/${base}.2.fastq.gz" >"./FinalCleaned/${base}.fastq.gz"
done

注意这里for 语句被赋予了正确的目录来查找文件。

【讨论】:

  • 谢谢,这非常有帮助!我的语法有点偏离,所以我在上面对其进行了编辑以供将来参考,但是你的 for 循环的结构工作得很好。
  • 嗨,约翰,另一个相关问题。当我运行附加到原始帖子底部的代码时,我收到了发布的错误。关于我哪里出错的任何建议?
【解决方案2】:

你可以使用类似的东西:

for fspec in *.fastq.gz ; do
    echo "${fspec}"
done

这将简单地回显正在处理的文件,但您可以对${fspec} 执行任何您想做的事情,包括将它用于几个zcat 命令。


为了获取文件名的root(用于创建其他文件),您可以使用bash的模式删除功能来删除尾随位:

for fspec in *.fastq.gz ; do
    froot=${fspec%%.fastq.gz}
    echo "Transform ${froot}.fastq.gz into ${froot}.1.fastq.gz"
done

此外,为了您的特定需要,您似乎希望将八行组的前四行发送到一个文件,将其他四行发送到第二个文件。

我倾向于只使用sed 来完成类似的简单任务,因为它可能会更快。您可以通过以下方式获得第一行组(八行中的前四行):

sed -n 'p;n;p;n;p;n;p;n;n;n;n'

第二个(八行中的后四行):

sed -n 'n;n;n;n;p;n;p;n;p;n;p'

使用p print-current 和n get-next 命令。

因此代码会变成这样:

for fsrc in *.fastq.gz ; do
    fdst1="${fspec%%.fastq.gz}.1.fastq.gz"
    fdst2="${fspec%%.fastq.gz}.2.fastq.gz"
    echo "Processing ${fsrc}"

    # For each group of 8 lines, fdst1 gets 1-4, fdst2 gets 5-8.
    zcat ${fsrc} | sed -n 'p;n;p;n;p;n;p;n;n;n;n' | gzip >${fdst1}
    zcat ${fsrc} | sed -n 'n;n;n;n;p;n;p;n;p;n;p' | gzip >${fdst2}
done

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多