forループに2つの変数を割り当てる方法は?

forループに2つの変数を割り当てる方法は?

私はパンゲノムパイプラインを実行しており、roaryforループ内にスクリプトを書く必要があります。たとえば、次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

(...)ループのサブシェルでローカルIFSにコンマに設定しました。つまり、"$*"カンマで区切られた現在位置引数のリストで構成される文字列に展開されます。

次に、ファイル名と他のファイル名をカンマ区切りリストとしてquery_pan_genome使用して$nameユーティリティを呼び出します。

サブシェルの後、ループ本体が終了する直前に現在の名前が位置引数リストに戻りますが、最後にあります。

リストを繰り返しても、ループ内の位置引数のリストを変更することに問題はありません。私たちが繰り返すリストは、ループ内でおよびを使用して変更されたshiftリストの変更不可能なコピーですsetforループは常に静的要素のリストを繰り返します)。

問題のGFFファイルのリストが与えられた場合、上記のコードは最終的に次の4つのコマンドを実行します。

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}配列の要素を に連結します,

代わりに、glob拡張オプションを持つglob修飾子を*.gff(N)使用してglobを有効にできます。*.gff(Nn)nnumericglobsortfile10.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

関連情報