저는 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개의 개별 배열에 로드한 다음 반복해야 합니다.한 번. 배열의 길이가 같은지 확인하는 것도 좋은 생각입니다.
bash
mapfile
텍스트 파일을 배열로 읽어들이는 내장 함수가 있습니다 . 기본 동작을 변경하는 옵션이 있지만 mapfile
기본적으로 입력 파일의 각 줄은 배열 요소에 로드됩니다. 또한 기본적으로 maparray
0이 배열의 원점으로 사용되지만 옵션을 사용하여 이를 재정의할 수 있습니다 -O
(예: -O 1
0 대신 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도 있습니다.