for 루프에 두 개의 변수를 할당하는 방법은 무엇입니까?

for 루프에 두 개의 변수를 할당하는 방법은 무엇입니까?

나는 판게놈 파이프라인을 실행해 왔으며 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수정한 목록의 변경 불가능한 복사본 입니다 set( for루프는 항상 정적 요소 목록을 반복합니다).

문제의 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}배열의 요소를 로 연결합니다 ,.

대신 , 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

관련 정보