Распаковать и повторно соединить текст фиксированной ширины - PullRequest
2 голосов
/ 07 мая 2020

У меня есть файл с разделителями фиксированной ширины, как показано ниже

aaaaa003aaaaaaaaaaaaaaa
bbbbb002aaaaaaaaaa
ccccc004cccccccccccccccccccc

Мне нужно получить его в форме

aaaaa003aaaaa
aaaaa003aaaaa
aaaaa003aaaaa
bbbbb002aaaaa
bbbbb002aaaaa
ccccc004ccccc
ccccc004ccccc
ccccc004ccccc
ccccc004ccccc

Мой текущий сценарий эффективен для 11 миллионов строк. Как я могу это оптимизировать?

#!/bin/sh
# My first Script
echo "Unbulking"
IN=$1
OUT=$2
while IFS= read -r line;do
    HEAD=${line:0:8}
    BODY=$(echo $line | sed -r ’s/.{8}//‘)
    BODYVAR=$(echo $BODY |fold -w 5)
    for i in ${BODYVAR}
    do
        echo $HEAD$i >> $OUT
    done
done < $IN
echo "Completed"

Мой лог c должен соответствовать строкам:

#take the first 8 characters of a line and assign to a str1
#take the last 3 characters of str1 and cast to a intger and assign to num1
#multiply num1 by 5 and assign to num2
#return the substring from char 8 to num2 and assign to str2
#cut str2 into chunks of 5 and assign to an array arr1
#concatenate str1 with each element of arr1
#return the arr1 as a set of new lines
#repeat for everyline in the file

Ответы [ 3 ]

2 голосов
/ 07 мая 2020

Не пытайтесь манипулировать текстом с помощью оболочки l oop, поскольку крайняя медленность, которую вы уже заметили, - это лишь одна из ваших проблем, см. почему-is-using-a-shell -l oop -to-process-text-Считается-плохой-практикой для этой проблемы и см. https://mywiki.wooledge.org/Quotes, https://mywiki.wooledge.org/DontReadLinesWithFor и Правильно Bash и использование заглавных букв в переменных сценария оболочки для некоторых других проблем в опубликованном вами сценарии.

Использование любого awk в любой оболочке в каждом поле UNIX:

$ cat tst.awk
{
    head = substr($0,1,8)
    tail = substr($0,9)
    while ( tail != "" ) {
        print head substr(tail,1,5)
        tail = substr(tail,6)
    }
}

.

$ awk -f tst.awk file
aaaaa003aaaaa
aaaaa003aaaaa
aaaaa003aaaaa
bbbbb002aaaaa
bbbbb002aaaaa
ccccc004ccccc
ccccc004ccccc
ccccc004ccccc
ccccc004ccccc
1 голос
/ 07 мая 2020

Весь ваш скрипт можно перевести на gawk вот так:

gawk 'BEGIN {
  FPAT=".{1,5}"
  OFS=""
}
{ head = substr($0,1,8)
  $0 = substr($0,9)
  for (i=1; i<=NF; i++)
    print head, $i
}' file
0 голосов
/ 07 мая 2020

Один для GNU awk. Это split запись по строке цифр и prints $1 цифр и $ 2 в 5 частях символов:

$ gawk '{
    split($0,a,/[0-9]+/,seps)
    while(length(a[2])) {
        print a[1] seps[1] substr(a[2],1,5)
        a[2]=substr(a[2],6) 
    }
}' file

Вывод:

aaaaa003aaaaa
aaaaa003aaaaa
aaaaa003aaaaa
bbbbb002aaaaa
bbbbb002aaaaa
ccccc004ccccc
ccccc004ccccc
ccccc004ccccc
ccccc004ccccc

Gnu awk только как он использует четвертый параметр split(), seps .

Обновление: Другая версия:

$ awk '{
    while(p=substr($0,9,5)) {
        print substr($0,1,8) p
        $0=substr($0,1,8) substr($0,14)
    }
}'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...