string.txt와 lengths.txt라는 두 개의 텍스트 파일이 있습니다.
문자열.txt:
abcdefghijklmnopqrstuvwxyz
길이.txt
5
4
10
7
파일을 받고 싶어요
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
저는 200자에서 56,000자 길이의 약 28,000개 항목을 작업하고 있습니다.
현재 나는 다음을 사용하고 있습니다 :
start=1
end=0
i=0
while read read_l
do
let i=i+1
let end=end+read_l
echo -e ">Entry_$i" >>outfile.txt
echo "$(cut -c$start-$end String.txt)" >>outfile.txt
let start=start+read_l
echo $i
done <lengths.txt
그러나 이는 매우 비효율적이다. 더 좋은 아이디어가 있나요?
답변1
일반적으로 말하면,텍스트를 처리하기 위해 쉘 루프를 사용하고 싶지 않습니다.. 여기서는 다음을 사용합니다 perl
.
$ perl -lpe 'read STDIN,$_,$_; print ">Entry_" . ++$n' lengths.txt < string.txt
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
그건하나(버퍼링을 사용하고 read
한 번에 1바이트(또는 일반 파일의 경우 여러 바이트)를 읽는 쉘 명령보다 더 효율적) 두 파일을 모두 한 번만 읽는(메모리에 완전히 저장하지 않고) 명령은 다음과 같습니다. 쉘 루프에서 외부 명령을 실행하는 솔루션보다 훨씬 더 효율적입니다.
( -C
숫자가 바이트가 아닌 현재 로케일의 문자여야 하는 경우 이 옵션을 추가하십시오. 예제의 ASCII 문자의 경우 차이가 없습니다.)
답변2
넌 할 수있어
{
while read l<&3; do
{
head -c"$l"
echo
} 3<&-
done 3<lengths.txt
} <String.txt
설명이 필요합니다.
주요 아이디어는 { head ; } <file
과소평가된 @mikeserv에서 사용 및 파생되었습니다.답변. 그러나 이 경우에는 많은 head
를 사용해야 하므로 while
루프가 도입되고 파일 설명자가 약간 조정되어 head
두 파일에 대한 입력이 전달됩니다(파일은 String.txt
처리할 기본 파일로, 행은 length.txt
인수로 전달됨). 옵션 -c
). 아이디어는 또는 String.txt
같은 명령이 호출될 때마다 검색할 필요가 없기 때문에 속도 이점이 있어야 한다는 것입니다. 각 반복 후에 개행 문자를 인쇄하세요.head
cut
echo
얼마나 빠른지 (만약 있다면) >Entry_i
연습으로 줄 사이에 내용을 추가하는 것입니다.
답변3
배쉬, 버전 4
mapfile -t lengths <lengths.txt
string=$(< String.txt)
i=0
n=0
for len in "${lengths[@]}"; do
echo ">Entry_$((++n))"
echo "${string:i:len}"
((i+=len))
done
산출
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
답변4
무엇에 대해 awk
?
다음 코드를 사용하여 라는 파일을 만듭니다 process.awk
.
function idx(i1, v1, i2, v2)
{
# numerical index comparison, ascending order
return (i1 - i2)
}
FNR==NR { a[FNR]=$0; next }
{ i=1;PROCINFO["sorted_in"] = "idx";
for (j in a) {
print ">Entry"j;
ms=substr($0, i,a[j])
print ms
i=i+length(ms)
}
}
저장 및 실행awk -f process.awk lengths.txt string.txt