Eu tenho dois arquivos de texto: string.txt e lengths.txt
String.txt:
abcdefghijklmnopqrstuvwxyz
lengths.txt
5
4
10
7
Eu quero pegar o arquivo
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
Estou trabalhando com cerca de 28.000 entradas e elas variam entre 200 e 56.000 caracteres.
No momento, estou usando:
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
Mas é muito ineficiente. Alguma ideia melhor?
linux
shell-script
user3891532
fonte
fonte
str="$(cat string.txt)"; i=0; while read j; do echo "${file:$i:$j}"; i=$((i+j)); done <length.txt
..seems rápido o suficiente como é feito apenas por shell ..{ while read l<&3; do head -c"$l"; echo; done 3<lengths.txt; } <String.txt
.Respostas:
Você pode fazer
Requer alguma explicação:
A idéia principal é usar
{ head ; } <file
e deriva da resposta subestimada @mikeserv . No entanto, neste caso, precisamos usar muitoshead
s, para que owhile
loop seja introduzido e um pouco de ajustes nos descritores de arquivo para passar para ahead
entrada de ambos os arquivos (arquivoString.txt
como arquivo principal para processar e linhaslength.txt
como argumento para-c
opção) . A idéia é que o benefício na velocidade deve vir da não necessidade de buscarString.txt
sempre que um comando é chamadohead
oucut
é invocado. Oecho
é apenas para imprimir uma nova linha após cada iteração.Quanto é mais rápido (se houver) e a adição
>Entry_i
entre linhas é deixada como exercício.fonte
read -u 3
de ler descritor 3.bash
. A grande maioria dos sistemas baseados em Linux não tembash
instalado (pense no Android e outros sistemas embarcados).bash
sendo o shell mais lento de todos, a mudança para o bash provavelmente diminuirá o desempenho mais significativamente do que o pequeno ganho que a mudança deread <&3
pararead -u3
pode trazer (que, em qualquer caso, será insignificante em comparação com o custo de executar um comando externo comohead
). Mudar para o ksh93 que foihead
incorporado (e que suporta a-c
opção não padrão ) melhoraria muito mais o desempenho.head -c
(para ashead
implementações em que essa opção não padrão está disponível) é um número de bytes, não caracteres. Isso faria diferença nos códigos de idioma de vários bytes.Geralmente, você não deseja usar loops de shell para processar texto . Aqui, eu usaria
perl
:Esse é um comando que lê (com buffer muito mais eficiente do que o
read
comando do shell que lê um byte (ou alguns bytes para arquivos regulares) por vez)) os dois arquivos apenas uma vez (sem armazená-los na memória), assim é será várias ordens de magnitude mais eficientes do que soluções que executam comandos externos em um loop de shell.(adicione a
-C
opção se esses números tiverem o número de caracteres no código do idioma atual, em vez do número de bytes. Para caracteres ASCII, como na sua amostra, isso não fará diferença).fonte
$_
parâmetros de saída e de entradaread
, mas reduz a contagem de bytes no script.bash
16 segundos comPATH=/opt/ast/bin:$PATH ksh93
)).bash, versão 4
resultado
fonte
Que tal
awk
?Crie um arquivo chamado
process.awk
com este código:Salve e execute
awk -f process.awk lengths.txt string.txt
fonte
PROCINFO
, isso não é padrãoawk
, masgawk
. Nesse caso, eu preferiria outrogawk
recurso único, oFIELDWIDTHS
:awk -vFIELDWIDTHS="$(tr '\n' ' ' < lengths.txt)" '{for(i=1;i<=NF;i++)print">Entry"i ORS$i}' string.txt