[unix] 텍스트 파일에서 문자열을 분리하는 빠른 방법?

string.txt와 lengths.txt라는 두 개의 텍스트 파일이 있습니다.

String.txt :

abcdefghijklmnopqrstuvwxyz

lengths.txt

5
4
10
7

파일을 받고 싶습니다

>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz

약 28,000 개의 항목을 작업 중이며 200 ~ 56,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

그러나 매우 비효율적입니다. 더 좋은 아이디어가 있습니까?



답변

넌 할 수있어

{
  while read l<&3; do
    {
      head -c"$l"
      echo
    } 3<&-
  done 3<lengths.txt
} <String.txt

설명이 필요합니다.

주요 아이디어는 사용 { head ; } <file하는 것이며 과소 평가 된 @mikeserv 답변 에서 파생됩니다 . 그러나이 경우 우리는 많은 heads 를 사용해야 하므로 두 파일 (입력 할 파일 의 주요 파일과 옵션 의 인수로 줄)에서 입력 while을 전달하기 위해 루프가 도입되고 파일 설명자와 약간 조정됩니다. . 아이디어는 속도가 좋아질 때 마다 명령을 받거나 호출 할 때마다 탐색 할 필요가 없다는 것입니다 . 는 각 반복 후 개행 문자를 인쇄 할 만하다.headString.txtlength.txt-cString.txtheadcutecho

얼마나 빠르며 (있는 경우) >Entry_i줄 사이에 추가 하는 것이 운동으로 남습니다.


답변

일반적으로 쉘 루프를 사용하여 text를 처리하고 싶지 않습니다 . 여기에 다음을 사용합니다 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 문자의 경우 아무런 차이가 없습니다.)


답변

bash, 버전 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


답변

무엇에 대해 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


답변