【问题标题】:How to stop bash loop from looping over files created during the loop?如何阻止 bash 循环遍历循环期间创建的文件?
【发布时间】:2021-11-21 08:41:34
【问题描述】:

我想对目录中特定扩展名的所有文件运行循环:

for i in *.bam
do
...
done

但是,如果我在循环中运行的命令创建了一个具有相同扩展名的临时文件,则循环也会尝试处理这个新的 tmp 文件。这是不希望的。因此,我认为以下方法可以解决问题:首先列出目录中的所有 *.bam 文件,将该列表保存到一个变量中,然后遍历这个保存的列表:

list_bam=$(for i in *.bam; do echo $i; done)

for i in $list_bam
do
...
done

令我惊讶的是,这遇到了同样的问题!有人可以解释一下这背后的逻辑以及如何解决它,以便循环只处理预先存在的 .bam 文件吗?

【问题讨论】:

  • echo $list_bam 没有给出列表。它只是给出*.bam。您可能必须将列表保存到文件并从中读取。
  • 当我在我的目录中运行list_bam=$(for i in *.bam; do echo $i; done),然后调用echo $list_bam,我得到了文件名列表。
  • 但是,如果我在循环中运行的命令创建了一个具有相同扩展名的临时文件,那么循环也会尝试处理这个新的 tmp 文件。 那是不可能的。
  • 这对我来说似乎也是不可能的,这就是我如此困惑的原因。
  • 我无法重现此问题。一个示例命令 for i in *.bam; do cp $i bu.$i; echo $i; sleep 0.1; done 仅适用于初始文件,正如人们所期望的那样。

标签: bash loops


【解决方案1】:

您或许应该确保您的通配表达式 *.bam 之后不会被解释为:

list_bam=$(ls *.bam)

...

...但是,正如@glenn 在 cmets 中所注意到的,这是一个坏主意。 应该使用find ... -print0 | xargs -0 ... 命令模板进行类似的操作。

【讨论】:

  • Why you shouldn't parse the output of ls -- list_bam=(*.bam) 然后for bam_file in "${list_bam[@]}" ...
  • 很好看。我相应地完善了答案。
  • 谢谢!这实际上解决了我现在的问题,我稍后会尝试实现find ... | xargs ...版本。
【解决方案2】:

你可以使用 find 和 xargs 来代替循环

find . -maxdepth 1 -type f -name "*.bam" -print0 | \
   xargs -0 -I{} bash -c 'echo "{}" > "{}.new.bam"'

find . -maxdepth 1 -type f -name "*.bam" -print0 | \
   xargs -0 -I{} bash -c 'echo "$1" > "$1.new.bam"' -- {}

示例:

$ touch a.bam b.bam
$ ls 
a.bam  b.bam
$ find . -maxdepth 1 -type f -name "*.bam" -print0 | \
    xargs -0 -I{} bash -c 'echo "{}" > "{}.new.bam"' 
$ ls
a.bam  a.bam.new.bam  b.bam  b.bam.new.bam

【讨论】:

  • 谢谢!我会尝试实现这个:)
猜你喜欢
  • 1970-01-01
  • 2014-11-19
  • 1970-01-01
  • 2012-07-25
  • 1970-01-01
  • 1970-01-01
  • 2016-06-21
  • 1970-01-01
  • 2013-09-20
相关资源
最近更新 更多