Codigo em Shell

1. Codigo em Shell

vagner fonseca
vagnerfonseca1

(usa Outra)

Enviado em 13/08/2018 - 13:55h

eu preciso de uma ajuda para otimizar o codigo abaixo, eu preciso ter um arquivo similar ao "arquivo_com_nome_dos_arquivos.txt" que possui o nome do arquivo porem com o path correto do arquivo.
Bem eu estou criando um arquivo com todos meus path dos arquivos depois estou lendo o arquivo com o nome dos arquivos substituindo pelo path completo e salvado em outro arquivo porem o processo esta muito.

find MEUDIRETORIO -name *.txt > arquivo_com_o_path_dos_arquivos.txt
i=0;
while read line
do
if [ $i -gt 0 ] ; then
line1=$(awk '{print $1}' <<< $line)
mypath=$(grep "$line1" arquivo_com_o_path_dos_arquivos.txt)
line=${line/${line1}/$mypath}
echo "$line" >> arquivo_com_path_mais_nome.txt
else
echo "$line" >> arquivo_com_path_mais_nome.txt
fi
i=`expr $i + 1`
done < arquivo_com_nome_dos_arquivos.txt



  


2. Re: Codigo em Shell

Marcelo Oliver
msoliver

(usa Debian)

Enviado em 13/08/2018 - 17:59h

vagnerfonseca1 escreveu:

eu preciso de uma ajuda para otimizar o codigo abaixo, eu preciso ter um arquivo similar ao "arquivo_com_nome_dos_arquivos.txt" que possui o nome do arquivo porem com o path correto do arquivo.
Bem eu estou criando um arquivo com todos meus path dos arquivos depois estou lendo o arquivo com o nome dos arquivos substituindo pelo path completo e salvado em outro arquivo porem o processo esta muito.

find MEUDIRETORIO -name *.txt > arquivo_com_o_path_dos_arquivos.txt
i=0;
while read line
do
if [ $i -gt 0 ] ; then
line1=$(awk '{print $1}' <<< $line)
mypath=$(grep "$line1" arquivo_com_o_path_dos_arquivos.txt)
line=${line/${line1}/$mypath}
echo "$line" >> arquivo_com_path_mais_nome.txt
else
echo "$line" >> arquivo_com_path_mais_nome.txt
fi
i=`expr $i + 1`
done < arquivo_com_nome_dos_arquivos.txt

Boa noite Vagner.
O path completo seria o caminho a partir da raiz,
exemplo:
home/user/BUSCADOR/SAVLOG/13082018.log
É isso que você quer?
Marcelo oliver



3. sim

vagner fonseca
vagnerfonseca1

(usa Outra)

Enviado em 13/08/2018 - 18:11h

Sim msoliver eu ja coloquei o path com a raiz usando o find


4. Re: Codigo em Shell

Marcelo Oliver
msoliver

(usa Debian)

Enviado em 13/08/2018 - 21:25h

vagnerfonseca1 escreveu:

Sim msoliver eu ja coloquei o path com a raiz usando o find


Fez isso utilizando o script mencionado acima?



5. Re: Codigo em Shell

vagner fonseca
vagnerfonseca1

(usa Outra)

Enviado em 14/08/2018 - 02:31h

vou comentar o codigo para vc entender o que eu estou fazendo


#crio um arquivo "arquivo_com_o_path_dos_arquivos.txt" com todos os path completo dos arquivos que preciso
find MEUDIRETORIO -name *.txt > arquivo_com_o_path_dos_arquivos.txt
i=0;
#faco um loop para pegar todos os nome dos arquivos que esta na primeira coluna do arquivo "arquivo_com_nome_dos_arquivos.txt"
while read line
do
if [ $i -gt 0 ] ; then #desconsidero a primeira linha do arquivo "arquivo_com_nome_dos_arquivos.txt" pois ha um cabeçalho
line1=$(awk '{print $1}' <<< $line) #extraio a primeira coluna que contem o nome do arquivo
mypath=$(grep "$line1" arquivo_com_o_path_dos_arquivos.txt) #localizo com o nome do arquivo o path completo criado no arquivo "arquivo_com_o_path_dos_arquivos.txt" pelo nome do arquivo
line=${line/${line1}/$mypath} #substituo a linha com o nome do arquivo pelo path completo do arquivo
echo "$line" >> arquivo_com_path_mais_nome.txt #salvo a informação correta em um outro arquivo
else
echo "$line" >> arquivo_com_path_mais_nome.txt #salvo o cabeçalho do arquivo
fi
i=`expr $i + 1`
done < arquivo_com_nome_dos_arquivos.txt



6. Re: Codigo em Shell

Paulo
paulo1205

(usa Ubuntu)

Enviado em 14/08/2018 - 14:53h

São muitos arquivos (i.e. tantos que é impossível trazer a lista inteira para a memória)?

Se não, use um array associativo.

#!/bin/bash

declare -A arq_path # Array associativo que mapeia arquivos para seus pathnames completos.

# Preenche o array associativo usando o find.
exec 3< <(find MEUDIRETORIO -type f -iname \*.txt) # Descritor 3 pega saída do find.
while read -u 3 path_arq; do
arq=$(basename "$path_arq")
arq_path["$arq"]="$path_arq"
done
exec 3<&- # Fecha descritor 3

# Lê nomes dos arquivos e faz a busca do pathname de cada um no array associativo,
# gravando a saída num arquivo.
exec 3< arquivo_com_nome_dos_arquivos.txt # Abre descritor 3 com arquivo com lista de nomes.
exec 4> arquivo_com_path_mais_nome.txt # (Re)cria arquivo de saída e associa ao descritor 4.
read -u 3 cabecalho
echo "$cabecalho" >&4
while read -u 3 arq; do
echo "${arq_path[$arq]-$arq}" >&4 # Se existe arquivo no array, imprime o valor; se não, imprime o arquivo.
done
exec 4>&- # Fecha descritor de arquivo de saída.
exec 3<&- # Fecha descritor com lista de nomes de arquivo.



7. Re: Codigo em Shell

vagner fonseca
vagnerfonseca1

(usa Outra)

Enviado em 14/08/2018 - 16:36h

Paulo esse é meu problema cada um desse arquivos possui quase 3 milhões de linhas de registro.


8. Re: Codigo em Shell

Paulo
paulo1205

(usa Ubuntu)

Enviado em 14/08/2018 - 16:59h

vagnerfonseca1 escreveu:

Paulo esse é meu problema cada um desse arquivos possui quase 3 milhões de linhas de registro.


Por isso a sua versão é lenta. Note que o grep dentro do laço de repetição, no seu programa original, lê o arquivo inteiro a cada iteração, para supostamente pegar uma única linha (e mesmo isso pode falhar: se você der um grep de "a.txt", pode pegar tanto "a.txt" qualquer outro arquivo cujo nome termine com "a.txt"). Essa é a maior vantagem da minha versão, pois ela lê cada linha de cada arquivo uma única vez, e as buscas feitas em memória usam um array associativo baseado em tabela hash, que teoricamente é uma busca de complexidade &#8771; O(1). O custo disso é o consumo de memória, que é proporcional à quantidade de linhas do primeiro arquivo.

Já tentou executar minha versão (depois de corrigir eventuais erros que eu tenha cometido, pois não testei o que vai ali)?

Se o consumo de memória for proibitivo, você poderia tentar uma abordagem parecida, mas com dados associativos gravados em disco, mas numa tabela hash ou árvore B, em lugar de arquivo linear de texto. Contudo, o acesso a esse tipo de dados a partir do shell possivelmente será sub-ótimo, pois cada consulta pode implicar a criação de um processo separado e a execução de um comando externo. Outras linguagens, como Perl ou Python (ou mesmo C ou C++), podem ajudar com esses dados em disco.


9. Re: Codigo em Shell

Marcelo Oliver
msoliver

(usa Debian)

Enviado em 14/08/2018 - 17:29h

vagnerfonseca1 escreveu:

vou comentar o codigo para vc entender o que eu estou fazendo


#crio um arquivo "arquivo_com_o_path_dos_arquivos.txt" com todos os path completo dos arquivos que preciso
find MEUDIRETORIO -name *.txt > arquivo_com_o_path_dos_arquivos.txt
i=0;
#faco um loop para pegar todos os nome dos arquivos que esta na primeira coluna do arquivo "arquivo_com_nome_dos_arquivos.txt"
while read line
do
if [ $i -gt 0 ] ; then #desconsidero a primeira linha do arquivo "arquivo_com_nome_dos_arquivos.txt" pois ha um cabeçalho
line1=$(awk '{print $1}' <<< $line) #extraio a primeira coluna que contem o nome do arquivo
mypath=$(grep "$line1" arquivo_com_o_path_dos_arquivos.txt) #localizo com o nome do arquivo o path completo criado no arquivo "arquivo_com_o_path_dos_arquivos.txt" pelo nome do arquivo
line=${line/${line1}/$mypath} #substituo a linha com o nome do arquivo pelo path completo do arquivo
echo "$line" >> arquivo_com_path_mais_nome.txt #salvo a informação correta em um outro arquivo
else
echo "$line" >> arquivo_com_path_mais_nome.txt #salvo o cabeçalho do arquivo
fi
i=`expr $i + 1`
done < arquivo_com_nome_dos_arquivos.txt


O código eu entendi...
Se você deseja o caminho completo, é só dar o find a partir da "raiz",
exemplo:
find /media/user/CASH_APT/ -iname "*.html" 

/media/user/CASH_APT/HTML/MOBILE/SENHA/APOIO/SENHA_Tab_01.html


10. Re: Codigo em Shell

Paulo
paulo1205

(usa Ubuntu)

Enviado em 14/08/2018 - 17:58h

Uma versão em Perl, gravando dados em disco em formato de tabela hash da biblioteca Berkeley DB.

#!/usr/bin/perl

use Fcntl;
use DB_File;

$data_file="/tmp/tempfile.$0.$<.$$.db";
$MEUDIRETORIO="/path/do/seu/diretorio";

# Faz com que o array associativo %arq_path grave dados em disco, usando DB_File como interface.
tie(%arq_path, "DB_File", $data_file, O_RDWR|O_CREAT|O_TRUNC, 0600, $DB_HASH) || die("Falha em tie: $!.\n");
unlink($data_file); # Truque: remove arquivo aberto com sucesso, de modo que, quando o programa terminar, mesmo que com erro, o espaço em disco será liberado.

# Preenche o array associativo usando o find.
open(FIND, "-|", "find", $MEUDIRETORIO, "-type", "f", "-iname", "*.txt") || die("Falha ao chamar find: $!.\n");
while(<FIND>){
chomp;
if(/^.*?\/+([^\/]+)$/){
$arq_path{$1}=$_;
}
}
close(FIND);

open(NOMES, "<", "arquivo_com_nome_dos_arquivos.txt") || die("Falha ao abrir arquivo de nomes: $!.\n");
open(SAIDA, ">", "arquivo_com_path_mais_nome.txt") || die ("Falha ao abrir arquivo de saída: $!.\n");
$cabecalho=<NOMES>;
print SAIDA $cabecalho;
while(<NOMES>){
chomp;
printf SAIDA "%s\n", (exists($arq_path{$_})? $arq_path{$_}: $_);
}
close(SAIDA);
close(NOMES);


Veja como o programa é parecido com o da versão em shell que eu mostrei — quase uma tradução linha a linha.


11. Resolvi o código assim.

vagner fonseca
vagnerfonseca1

(usa Outra)

Enviado em 16/08/2018 - 04:10h

Tenho dois dias tentando responder que consegui.
Obrigado pelo empenho de todos, consegui resolver o código desta maneira

find PATH_DIRETORIO -name *.txt | awk '{n=split($0, c, "/") ; system( "echo " c[n] "\t" $0 )}' > arq_com_nome_e_path_dos_arquivos.txt
cat arq_com_nome_e_path_dos_arquivos.txt | awk '{print $1,$2}' | sort -k1,1 > arq_com_nome_e_path_dos_arquivos_sort.txt
sed '1d' arq_com_nome_dos_arquivos.txt | awk '{print $1,$2}' | sort -k1,1 > arq_com_nome_dos_arquivos_sort.txt
join -11 -11 arq_com_nome_dos_arquivos_sort.txt arq_com_nome_e_path_dos_arquivos_sort.txt > arq_final_com_nome__e_path_dos_arquivos.txt







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts