For 루프는 여러 파일에서 그립니다.

For 루프는 여러 파일에서 그립니다.

저는 Unix를 처음 접하고 R에서 사용하던 스크립트를 변환하고 싶습니다. 이를 위해 파일 이름 변형이 서로 다른 세 개의 파일(동일한 길이)이 있습니다. 각 파일에서 한 줄을 가져와 세 파일 모두를 한 줄씩 반복하고 싶습니다. 하지만 여러 변수를 for 루프에 통합하는 방법을 잘 모르겠습니다.

module load bbtools 

for i in fna and j in fna2 and k in fna.prefix; 
do 
rename.sh -Xmx20g in=",${i}," out=",${j}" prefix=",${k}"
done

R 스크립트를 호출하지 않고 직접 실행할 수 있는 방법이 있습니까?

답변1

이 명령을 사용할 수 있습니다 paste. 파일의 경우:

a.txt

1
2
3

b.txt

a
b
c

c.txt

z
x
y

명령 출력의 예는 다음과 같습니다.

$ paste -d, a.txt b.txt c.txt
1,x,a
2,y,b
3,z,c

그런 다음 파이프할 수 있습니다(올바른 구분 기호, 즉 명령에서 사용한 구분 기호 사용 paste).

paste -d, a.txt b.txt c.txt | while IFS=',' read -r f1 f2 f3; do
    # do your task with $f1 $f2 $3
done

답변2

3개의 파일을 3개의 개별 배열에 로드한 다음 반복해야 합니다.한 번. 배열의 길이가 같은지 확인하는 것도 좋은 생각입니다.

bashmapfile텍스트 파일을 배열로 읽어들이는 내장 함수가 있습니다 . 기본 동작을 변경하는 옵션이 있지만 mapfile기본적으로 입력 파일의 각 줄은 배열 요소에 로드됩니다. 또한 기본적으로 maparray0이 배열의 원점으로 사용되지만 옵션을 사용하여 이를 재정의할 수 있습니다 -O(예: -O 10 대신 1에서 배열 시작).

bash에서 실행 help mapfile하거나 bash 매뉴얼 페이지에서 맵 파일에 대한 자세한 내용을 검색하세요.

예를 들어:

#!/bin/bash

# load the three files into arrays a, b, and c.
mapfile -t -O 1 a < fna
mapfile -t -O 1 b < fna2
mapfile -t -O 1 c < fna.prefix

# check if they're the same length    
if [ "${#a[@]}" != "${#b[@]}" ] || [ "${#a[@]}" != "${#c[@]}" ]; then
  echo "input files are not the same length"
  exit 1
fi

# do something with them, iterating from 1 to the length of array a.    
for i in $(seq 1 "${#a[@]}"); do
  rename.sh -Xmx20g in=",${a[i]}," out=",${b[i]}" prefix=",${c[i]}"
done

참고: 이 3개의 파일이 각각 수백만 또는 수십억 줄로 구성되어 있으면 실현 불가능한 양의 메모리를 사용하게 됩니다. 한 번에 3개의 파일을 쉽게 열고 루프가 반복될 때마다 각 파일에서 한 줄을 읽을 수 있는 언어를 사용하는 것이 더 좋습니다. 예를 들어 awk, perl, python, C 등, 심지어 R도 있습니다.

관련 정보