【问题标题】:Read list of files on unix and run command读取 unix 上的文件列表并运行命令
【发布时间】:2013-08-04 10:01:27
【问题描述】:

我是 shell 脚本的新手,我整天都在努力弄清楚如何执行“for”命令。本质上,我想做的是以下几点:

我有一个包含一堆名称的 list.txt 文件:

name1
name2
name3

对于列表中的每个名称,都有两个不同的文件,每个文件的名称都有不同的结尾。例如:

name1_R1
name1_R2

我尝试运行的程序名为sickle。基本上,它需要两个文件(彼此对应)并对它们进行分析,因此需要我有这个命名方案。镰刀命令如下:

sickle pe -f input_file1.fastq -r input_file2.fastq -t sanger \

如果有人可以帮助我,至少只是告诉我如何让 unix 读取文件列表并独立处理每一行,我想我可以从那里开始。我尝试了一些方法,但都没有奏效。

【问题讨论】:

  • 欢迎来到 Stack Overflow。请尽快阅读About 页面。您的示例命令行与您在文件中列出的名称或从name1 生成的名称没有太大关系,这使得您很难猜出您真正想看到的内容。写出你的问题的一致性可以更容易地给你一个有用的答案。请显示您要为文件库name1 生成的确切命令行。尾部反斜杠的意义是什么?此外,最好展示您尝试过的一些方法,而不是抽象地声称它们不起作用。

标签: bash list loops unix fastq


【解决方案1】:

使用while 循环和read

while read fn; do
    <command> "${fn}_R1" "${fn}_R2"
done < list.txt

【讨论】:

  • 这与 `cat fn` 的原始版本存在相同的问题:带有空格的文件名将不起作用,因为命令会收到太多的参数。改用"${fn}_R1""${fn}_R2"
  • 谢谢,已修改。我以前编写脚本时没有让它们空间安全,但最近尝试学习空间安全的做事方式。还在调整中;)
  • 您甚至不需要指定 fn。 Bash 会自动分配给 REPLY,这通常就足够了,除非您在每次读取时分配给多个变量。
  • @CodeGnome:我喜欢明确我的变量名。写while read; do &lt;command&gt; $REPLY 对我来说有点太“神奇”了。
【解决方案2】:

使用 Bash For 循环

Bash 有一个非常合理的 for 循环作为其 looping constructs 之一。您可以将下面的 echo 命令替换为您想要的任何自定义命令。例如:

for file in name1 name2 name3; do
  echo "${file}_R1" "${file}_R2"
done

想法是循环将每个文件名分配给 file 变量,然后将 _R1 和 _R2 后缀附加到它们。请注意,引用可能很重要,并且在不需要时也无害,因此您应该将其用作防御性编程措施。

对参数列表使用 xargs

如果你想从文件中读取而不是直接使用 for 循环,你可以使用 Bash 的 read builtin,但 xargs 通常更易于跨 shell。例如,以下使用来自 GNU findutilsxargs 版本中可用的标志从文件中读取参数,然后为每个参数附加一个后缀:

$ xargs --arg-file=list.txt --max-args=1 -I{} /bin/echo "{}_R1" "{}_R2"
name1_R1 name1_R2
name2_R1 name2_R2
name3_R1 name3_R2

同样,您可以将“echo”替换为您选择的命令行。

【讨论】:

  • 依赖 GNU xargs 通常不如仅仅依赖 Bash 可移植。很多系统都带有 Bash(即使你的 shell 不是),但很少有系统带有 GNU 实用程序(例如,Solaris、OS X、BSD...)
  • 如果您的xargs 版本没有--arg-file 选项,您也可以将文件重定向到STDINxargs -I{} /bin/echo "{}_R1" "{}_R2" &lt; list.txt
【解决方案3】:

有几种方法可以做到这一点。由于数据文件中的名称是“每行一个”,我们可以假设文件名中没有换行符。

for循环

for file in $(<list.txt)
do
    sickle pe -f "${file}_file1.fastq" -r "${file}_file2.fastq" -t sanger
done

whileread 循环

while read file
do
    sickle pe -f "${file}_file1.fastq" -r "${file}_file2.fastq" -t sanger
done < list.txt

for 循环仅在名称中没有空格(也没有其他空白字符,如制表符)时才有效。只要名称中没有换行符,while 循环就是干净的,尽管使用 while read -r file 可以更好地防止意外情况发生。 for 循环中文件名周围的双引号是装饰性的(但无害),因为文件名不能包含空格,但 while 循环中的双引号可防止包含空格的文件名在不应拆分时被拆分。每次使用变量时引用变量通常是个好主意,但严格来说,只有当变量可能包含空格但您不希望值被拆分时才有意义。

我不得不猜测应该将哪些名称传递给 sickle 命令,因为您的问题并不清楚 — 我 99% 确定我猜错了,但它与您示例中的不同后缀匹配命令假设文件的基本名称是input。我省略了尾随反斜杠;它是 'escape' 字符,不清楚你在那里真正想要什么。

【讨论】:

  • 就像一个魅力。非常感谢!是的,我不想把这个名字列入名单,因为我认为这样做会更简单。
  • mywiki.wooledge.org/DontReadLinesWithFor while 循环应该是这里的第一个建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-11
  • 1970-01-01
  • 2013-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多