如何在一个for循环中分配两个变量?

如何在一个for循环中分配两个变量?

我一直在运行roarypangenome 管道,我需要在 for 循环中编写一个脚本,例如我有一个gff文件如下,

a.gff
b.gff
5.gff
101.gff
clustered_proteins

我需要运行一个命令来从roary管道中检索独特的基因,如下所示,

query_pan_genome -a difference --input_set_one a.gff --input_set_two b.gff,5.gff,101.gff -g clustered_proteins
 
query_pan_genome -a difference --input_set_one b.gff --input_set_two a.gff,5.gff,101.gff -g clustered_proteins

query_pan_genome -a difference --input_set_one 5.gff --input_set_two a.gff,b.gff,101.gff -g clustered_proteins

query_pan_genome -a difference --input_set_one 101.gff --input_set_two a.gff,b.gff,5.gff -g clustered_proteins

为了做同样的事情,我编写了一个脚本,如下所示,

file1=*.gff
file2=*.gff
file3="-f "$file1-$file2"
for file in *.gff
do
query_pan_genome -a difference --input_set_one "$file1" --input_set_two "$file3" -g clustered_proteins 
done

但是上面的脚本没有达到我的目的,我只知道脚本很简单,这对我来说很难写。请帮助我完善剧本。

提前致谢。

答案1

使用/bin/sh

#!/bin/sh

set -- *.gff
for name do
    shift
    (   IFS=,
        query_pan_genome -a difference \
            --input_set_one "$name" \
            --input_set_two "$*" \
            -g clustered_proteins
    )
    set -- "$@" "$name"
done

这首先将位置参数设置为与模式匹配的文件名列表*.gff。然后循环遍历该列表,将变量设置name为当前文件名的值。

在循环中,对于每个文件名,第一个位置参数将从位置参数列表中移出。这个移出的元素对应于也在 中找到的当前文件名$name。在 后shift,位置参数列表包含其他文件名,但不包含$name.

(...)循环的子shell中,我们本地设置IFS为逗号。这意味着它将"$*"扩展为由当前位置参数列表组成的字符串,并以逗号作为分隔符。

然后,我们query_pan_genome使用$name文件名和其他文件名作为逗号分隔列表来调用该实用程序。

在 subshel​​l 之后,就在循环体结束之前,当前名称被放回到位置参数列表中,但在最后。

即使我们迭代该列表,修改循环内的位置参数列表也没有问题。我们迭代的列表是我们在循环中使用shiftand修改的列表的不变副本setfor循环始终迭代静态元素列表)。

鉴于问题中的 GFF 文件列表,上面的代码最终将执行以下四个命令:

query_pan_genome -a difference --input_set_one 101.gff --input_set_two 5.gff,a.gff,b.gff -g clustered_proteins
query_pan_genome -a difference --input_set_one 5.gff --input_set_two a.gff,b.gff,101.gff -g clustered_proteins
query_pan_genome -a difference --input_set_one a.gff --input_set_two b.gff,101.gff,5.gff -g clustered_proteins
query_pan_genome -a difference --input_set_one b.gff --input_set_two 101.gff,5.gff,a.gff -g clustered_proteins

答案2

使用以下方法更容易zsh

#! /bin/zsh -
files=(*.gff(N))

# don't run that command if there are fewer than 2 files
(( $#files < 2 )) ||
  for f ($files)
    query_pan_genome -a difference \
                     --input_set_one $f \
                     --input_set_two ${(j[,])files:#$f} \
                     -g clustered_proteins

在哪里

  • ${array:#pattern}扩展到数组中与模式不匹配的元素,因此这里使用except${files#$f}的元素。$files$f
  • ${(j[,])array}将数组的元素与 相连,

而不是*.gff(N),您可能希望使用*.gff(Nn)globn限定符打开numericglobsort该 glob 扩展选项的位置,这样就file10.gff可以了 file2.gff例如。

答案3

您可以使用数组,循环其索引并暂时取消设置每个索引:

#! /bin/bash

input_files=(*.gff)

IFS=,
for index in "${!input_files[@]}"
do
    input_file=${input_files[$index]}
    unset input_files[$index]
    echo "$input_file" "${input_files[*]}"
    input_files[$index]=$input_file
done

输出示例:

101.gff 5.gff,a.gff,b.gff
5.gff 101.gff,a.gff,b.gff
a.gff 101.gff,5.gff,b.gff
b.gff 101.gff,5.gff,a.gff

相关内容