【问题标题】:For loop within a for loop for iterating files of different extensions用于迭代不同扩展名的文件的for循环中的for循环
【发布时间】:2019-06-13 14:38:35
【问题描述】:

假设我有 20 个不同的文件。前 10 个文件以 .counts.tsv 结尾,其余文件以 .libsize.tsv 结尾。对于每个.counts.tsv,都有匹配的.libsize.tsv 文件。我想使用 for 循环来选择这两个文件并为这两种文件类型运行 R 脚本。 这是我尝试过的,

#!/bin/bash
arti='/home/path/tofiles'
for counts in ${arti}/*__counts.tsv ; do
    for libsize in "$arti"/*__libsize.tsv ; do
        Rscript score.R  ${counts} ${libsize}
 done;
done;

上面的 shell 脚本迭代文件超过 200 次,而我只有 20 个文件。我需要为这两个文件执行 10 次 Rscript。任何建议将不胜感激。

【问题讨论】:

  • 你想在这个脚本结束时做什么?
  • 最后,我需要在每个countslibsize上执行R脚本
  • "两个文件 10 次" 所以总共 20 次迭代?希望文件以相似的第一部分命名,即你有myFile.libsize.tsvmyFile.__counts.tsv 然后你只需要1个循环,从循环返回的变量中去掉扩展名并将其添加回你的@上的2个副本987654330@线,即。 Rscript ${myF}.__counts.tsv ${myF}.__libsize.tsv。祝你好运。
  • Rscript 应该只运行 10 次。因此,10 次迭代。所以我想我需要在这里更清楚一点,对于每个.count.tsv 文件,都有一个匹配的.libsize.tsv,因此总共有 20 个。因此,最后 Rscript 应该只迭代 10 次
  • 啊,那我们把R标签去掉吧。

标签: shell for-loop


【解决方案1】:

在看到您只对 bash 解决方案感兴趣的评论之前,我开始输入答案,无论如何都会发布,以防将来有人发现此问题并对基于 R 的解决方案持开放态度。

如果我从头开始处理这个问题,我可能只是使用文件中定义的 R 函数来获取两个文件名,而不是搞乱system() 调用,但这会提供你想要的行为。

## Get a vector of files matching each extension
counts_names <- list.files(path = ".", pattern ="*.counts.tsv")
libsize_names <- list.files(path = ".", pattern ="*.libsize.tsv")

## Get the root names of the files before the extensions
counts_roots <- gsub(".counts.tsv$", "",counts_names)
libsize_roots <- gsub(".libsize.tsv$", "",libsize_names)

## Get only root names that have both file types
shared_roots <- intersect(libsize_roots,counts_roots)

## Loop through the shared root names and execute an Rscript call based on the two files
for(i in seq_along(shared_roots)){

  counts_filename <- paste0(shared_roots[[i]],".counts.tsv")
  libsize_filename <- paste0(shared_roots[[i]],".libsize.tsv")

  Command  <- paste("Rscript score.R",counts_filename,libsize_filename)
  system(Command)

}

【讨论】:

    【解决方案2】:

    ${counts%counts.tsv} 构造第二个文件名(删除最后一部分)。

    #!/bin/bash
    arti='/home/path/tofiles'
    for counts in ${arti}/*__counts.tsv ; do
        libsize="${counts%counts.tsv}libsize.tsv"
        Rscript score.R "${counts}" "${libsize}"
    done
    

    编辑:
    不太安全的是试图使它成为一个单线。当文件名没有空格和换行符时,您可能会遇到意外

    echo ${arti}/*counts.tsv ${arti}/*.libsize.tsv | xargs -n2 Rscript score.R
    

    当你感到非常幸运(除了$arti 中的 tsv 文件之外没有其他文件)时,可以使用

    echo ${arti}/* | xargs -n2 Rscript score.R
    

    【讨论】:

    • 谢谢,我在下面发布了另一个解决方案:)
    • 您的解决方案是相同的想法,同时使用basenameawk 更慢。在这种情况下,性能无关紧要,当您想要遍历大文件并为每一行做一些事情时,它会很重要。
    【解决方案3】:

    你试过list.files 吗?这将允许您使用文件夹中的所有文件。

    arti='/home/path/tofiles'
    for i in list.files(arti) {
      script
    }
    

    【讨论】:

    • 我需要的文件有两个不同的扩展名。假设我有以 counts.tsvlibsize.tsv 结尾的文件,需要为 Rscript 单独选择这些文件。因此,您的解决方案将不起作用。
    • @user1017373:不过,这几乎肯定会是正确的工具。也许您需要在获得列表后以某种方式将其分开?请澄清问题,不清楚每种类型的 10 个文件如何让脚本只运行 10 次。有些事情你没有告诉我们......
    • @Aaron,感谢您的评论。是的,例如,我有 10 个样本,其中包含 counts.tsv 文件和一个匹配的 libsize.tsv 文件。因此,最后我只需要 10 次迭代,但是在文件夹中我有 20 个文件
    【解决方案4】:

    看看以下是否有帮助。

    my_list = list.files("./Data")
    counts = grep("counts.tsv", my_list, value=T)
    libsize = grep("libsize.tsv", my_list, value=T)
    
    for (i in seq(length(counts))){
      system(paste("Rscript score.R",counts[i],libsize[i]))
    }
    

    【讨论】:

    • 这似乎是 bash 和 R 的混合体,因此实际上不会运行;我错过了什么吗?
    • 这个想法是将两个文件同时带入 for 循环。编辑答案。
    【解决方案5】:

    最后,

    我尝试了以下方法,它对我有帮助,

    for sam in "$arti"/*__counts.tsv ; do
          filebase=$(basename $sam)
          samples=$(ls -1 ${filebase}|awk -F'[-1]' '{print $1}')
            Rscript score.R ${samples}__counts.tsv ${samples}__libsize.tsv
     done;
    

    对于寻找类似东西的人:)

    【讨论】:

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