Como pegar linhas de um arquivo de jogar em outros arquivos [RESOLVIDO]

1. Como pegar linhas de um arquivo de jogar em outros arquivos [RESOLVIDO]

icaro
icaroamerico222

(usa Outra)

Enviado em 02/12/2020 - 16:58h

Bom dia!

Criei um Shellscript para ler um arquivo posicional, pegar uma determinada posição e baseada nessa posição jogar a linha inteira para outro arquivo.

Segue um exemplo:

INPUT FILE
003402841000011A10CNPJ08963394000195
003402841000041B20CNPJ08963394000195 16012020XX5313720087903007
003402841000011A10CNPJ08963394000195
003402841000041B20CNPJ08963394000195 16012020XX5313720087903007

OUTPUT FILE A
003402841000011A10CNPJ08963394000195
003402841000011A10CNPJ08963394000195

OUTPUT FILE B
003402841000041B20CNPJ08963394000195 16012020XX5313720087903007
003402841000041B20CNPJ08963394000195 16012020XX5313720087903007

Tenho o seguinte codigo:


#!/usr/bin/env bash

ARQ_IN="$1";
DIR_OUT="C:/Users/etc/etc/'";

while IFS= read -r line || [[ -n "$line" ]];
do

SUBSTRING=$(echo $line| cut -c16);

if [ $SUBSTRING == "A" ]
then
echo "$line" >> "$DIR_OUT"arqA.txt;
else
if [ $SUBSTRING == "B" ]
then
echo "$line" >> "$DIR_OUT"arqB.txt;
else
if [ $SUBSTRING == "K" ]
then
echo "$line" >> "$DIR_OUT"arqK.txt;
else
if [ $SUBSTRING == "1" ]
then
echo "$line" >> "$DIR_OUT"arq1.txt;
else

fi
fi
fi
fi


done < "$ARQ_IN"


O codigo acima faz o que eu quero, porém demora demais, o arquivo que estou lendo tem em torno de 400k de registros.

Gostaria de saber se consigo melhorar o meu codigo ou algum outro que me ajude.

Obrigado!


  


2. Re: Como pegar linhas de um arquivo de jogar em outros arquivos

Marcelo Oliver
msoliver

(usa Debian)

Enviado em 02/12/2020 - 18:19h

icaroamerico222 escreveu:

Bom dia!

Criei um Shellscript para ler um arquivo posicional, pegar uma determinada posição e baseada nessa posição jogar a linha inteira para outro arquivo.

Segue um exemplo:

INPUT FILE
003402841000011A10CNPJ08963394000195
003402841000041B20CNPJ08963394000195 16012020XX5313720087903007
003402841000011A10CNPJ08963394000195
003402841000041B20CNPJ08963394000195 16012020XX5313720087903007

OUTPUT FILE A
003402841000011A10CNPJ08963394000195
003402841000011A10CNPJ08963394000195

OUTPUT FILE B
003402841000041B20CNPJ08963394000195 16012020XX5313720087903007
003402841000041B20CNPJ08963394000195 16012020XX5313720087903007

Tenho o seguinte codigo:


#!/usr/bin/env bash
ARQ_IN="$1";
DIR_OUT="C:/Users/etc/etc/'";

while IFS= read -r line || [[ -n "$line" ]]; do
SUBSTRING=$(echo $line| cut -c16);
if [ $SUBSTRING == "A" ];then
echo "$line" >> "$DIR_OUT"arqA.txt;
else
if [ $SUBSTRING == "B" ];then
echo "$line" >> "$DIR_OUT"arqB.txt;
else
if [ $SUBSTRING == "K" ];then
echo "$line" >> "$DIR_OUT"arqK.txt;
else
if [ $SUBSTRING == "1" ];then
echo "$line" >> "$DIR_OUT"arq1.txt;
else
fi
fi
fi
fi


done < "$ARQ_IN"


O codigo acima faz o que eu quero, porém demora demais, o arquivo que estou lendo tem em torno de 400k de registros.

Gostaria de saber se consigo melhorar o meu codigo ou algum outro que me ajude.

Obrigado!

Boa noite Icaro.
segue solução:

awk -F '' '{if($16=="A") arq="FILE_A"; else if($16=="B") arq="FILE_B"; else if($16=="K") arq="FILE_K";else if($16=="1") arq="FILE_1"; print $0 > arq}' INPUT.txt
Encolhi o comando, creio que desta forma é mais rápido do que a anterior, visto que não existem condicionais
awk -F '' '{arq="FILE_"$16".txt"; print $0 > arq}' INPUT.txt
Seu script:
Não é necessário em cada else, abrir outro condicional, veja:
#!/usr/bin/env bash

ARQ_IN="$1";
DIR_OUT="C:/Users/etc/etc/'";

while IFS= read -r line || [[ -n "$line" ]]; do

SUBSTRING=$(echo $line| cut -c16);

if [ $SUBSTRING == "A" ];then
echo "$line" >> "$DIR_OUT"arqA.txt;
elif [ $SUBSTRING == "B" ];then
echo "$line" >> "$DIR_OUT"arqB.txt;
elif [ $SUBSTRING == "K" ];then
echo "$line" >> "$DIR_OUT"arqK.txt;
elif [ $SUBSTRING == "1" ];then
echo "$line" >> "$DIR_OUT"arq1.txt;
fi
done < "$ARQ_IN"
---------------------------------------------------------------------
#Pode trocar o "IF" pelo case:
while IFS= read -r line || [[ -n "$line" ]]; do
SUBSTRING=$(cut -c16 <<< "$line");

case $SUBSTRING in
A) echo "$line" >> "$DIR_OUT"arqA.txt;;
B) echo "$line" >> "$DIR_OUT"arqB.txt;;
K) echo "$line" >> "$DIR_OUT"arqK.txt;;
1) echo "$line" >> "$DIR_OUT"arq1.txt;;
esac
done < "$ARQ_IN"



______________________________________________________________________
Importante: lynx --dump goo.gl/a9KeFc|sed -nr '/^[ ]+Se/,/dou.$/p'
Att.: Marcelo Oliver
______________________________________________________________________
Nota de esclarecimento:
O comando: lynx --dump goo.gl/a9KeFc|sed -nr '/^[ ]+Se/,/dou.$/p',
faz parte da minha assinatura.
O qual, "filtra" a página: "https://www.vivaolinux.com.br/termos-de-uso/",
Mostrando o seguinte:

Se você sanou sua dúvida ou resolveu um problema a partir de um
tópico criado, é extremamente recomendável que acesse o tópico e
marque-o como "RESOLVIDO". E mais recomendável ainda que você eleja
como melhor resposta a que mais lhe ajudou.


______________________________________________________________________



3. Re: Como pegar linhas de um arquivo de jogar em outros arquivos

opera
opera20

(usa Outra)

Enviado em 03/12/2020 - 07:52h

Ler linha por linha no loop de bash é um pouco lento.

Mas dá para ele ficar um pouco mais rápido fazendo algumas coisas.
Primeiro, usando-se um exec para abrir o arquivo ao invés
de usar o a redireção de shell diretamente no loop, *pode ser* um pouco
mais rápido em alguns casos.

Aquele teste [[ -n "$line" ]] acredito não ser necessário
pois o read vai sair com 1 se não ler nada, ou seja,
quando chegar na última linha do arquivo.
Menos um teste.

E talvez o mais importante,
usar o teste [[ ]] ao invés de [ ].
O teste [ ] é mais antigo e na verdade, a shell
abre uma subshell quando se usa esse
constructo ou o comando 'test' ao invés do [[ ]],
mais moderno, mais ráido e executado na
shell corrente.

Só que, o case é muito mais rápido
do que o if+elifs.


Para ficar mais rápido, dá para tirar o cut.
Usa-se o bash para puxar um caracter
a partir do 15º caracter, ou seja,
o 16º caracter.
Lembrando-se que a contagem no bash começa do 0.


Sugestão

#!/usr/bin/bash
ARQ_IN="$1";
DIR_OUT="C:/Users/etc/etc/'";

exec 0<"$ARQ_IN"

while IFS= read -r line
do
SUBSTRING="${line:15:1}"

case "$SUBSTRING" in
A)
echo "$line" >> "$DIR_OUT"arqA.txt
;;
B)
echo "$line" >> "$DIR_OUT"arqB.txt
;;
K)
echo "$line" >> "$DIR_OUT"arqK.txt
;;
1)
echo "$line" >> "$DIR_OUT"arq1.txt
;;
esac
done