shell-script-pt
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [shell-script] Desempenho ao checar se string existe em arquivo de t


From: Julio C. Neves
Subject: Re: [shell-script] Desempenho ao checar se string existe em arquivo de texto
Date: Wed, 24 Dec 2014 11:03:00 -0200

Fala Mercês,
vens para o RJ passar o fim de ano? Se vier um (mentira, diversos) chope te espera...

Cara vc já tentou usar a opção -f do grep ou do sed? São super otimizadas.

Um pouco de teoria (da 10aª edição do meu livro que finalmente deve ser lançada em Janeiro)
=======================================

A opção -f

Vamos pegar um pedaço de /etc/passwd e colocá-lo no arquivo passwd.tmp:

$ tail -7 /etc/passwd > passwd.tmp

Veja como ele ficou (os que terminam em reticências foram cortados porque são dados que não interessam ao caso e para não haver quebra de linha que prejudicaria a legibilidade):

$ cat passwd.tmp

bin:x:2:2:bin:/bin:/bin/sh

pulse:x:109:114:PulseAudio daemon,,,:/var/run/pulse:...

rtkit:x:110:117:RealtimeKit,,,:/proc:/bin/false

saned:x:111:118::/home/saned:/bin/false

hplip:x:112:7:HPLIP system user,,,:/var/run/hplip:...

gdm:x:113:120:Gnome Display Manager:/var/lib/gdm:...

julio:x:1000:1000:Julio Neves,,,:/home/julio:/bin/bash

postfix:x:114:123::/var/spool/postfix:/bin/false

Tenho um outro arquivo com logins names que desejo excluir de passwd.tmp.

$ cat exclui

postfix

hplip

gdm

bin

pulse

Eu posso, usando a opção -f ARQUIVO do sed, excluir direto de passwd.tmp os registros dos usuários indicados em exclui, mas antes preciso prepará-lo para que ele, que agora só tem os nomes dos usuários, passe a ter o comando de deleção do sed, no formato:

/^USUARIO:/d

Onde as barras (/) e o d formam a sintaxe do comando e o circunflexo (Expressão Regular que indica inicio de linha) e os dois pontos (:) marcam os limites da palavra. Se esses limites não fossem estipulados, todos os registros de passwd.tmp que contivessem, por exemplo, a palavra bin - mesmo como parte de outra maior - seriam deletados).

Preparando exclui:

$ sed -i 's|^|/^|;s|$|:/d|' exclui

$ cat exclui

/^postfix:/d

/^hplip:/d

/^gdm:/d

/^bin:/d

/^pulse:/d

Como você notou, usamos a barra vertical (|) como delimitador e o ponto e vírgula (;) serviu para usarmos dois comandos substitute (s) dentro do mesmo sed.

Observação: A explicação para o uso do ponto e vírgula (;), está na seção a seguir.

Agora que todos os comandos já estão montados, podemos proceder à deleção. Veja como:

$ sed -i -f exclui passwd.tmp

$ cat passwd.tmp

rtkit:x:110:117:RealtimeKit,,,:/proc:/bin/false

saned:x:111:118::/home/saned:/bin/false

julio:x:1000:1000:Julio Neves,,,:/home/julio:/bin/bash

Isto é a opção -f informou o nome do arquivo de comandos para o sed (exclui) utilizar e em seguida, informamos o arquivo a ser alterado (passwd.tmp). Como usamos a opção -i, as alterações foram feitas diretamente no último.

=======================================

Mas no teu caso, que é praticamente idêntico, podemos fazer assim:

Vamos preparar cada linha do arquivo para listar todos os registros que forem encontrados em $outfile. Para isso vamos preceder cada nome com um /^ e sucedê-los com um :/p. Digamos que um registro seja aaaa, ao fim da execução de:
$ sed -i 's|^|/^|;s|$|:/p|' $outfile
Ele ficará /^aaaa:/p, que seria o cmd  do sed para imprimir. Então vamos listar os que já existem:
$ sed -n -f $outfile /etc/passwd | xargs -I{} echo o registro {} já existe

Se vc caprichar, põe tudo em um sed somente.


Abcs,
Julio
@juliobash
P
róximos cursos de Shell
Cidade         Local Período
Rio de Janeiro EDX 09 a 13/03/15
São Paulo 4Linux 24 a 28/11/14
Dou treinamento de Shell em qualquer cidade.
Para mais detalhes, me mande um e-mail.


Em 23 de dezembro de 2014 23:36, Fernando Mercês address@hidden [shell-script] <address@hidden> escreveu:
 

Amigos,

Num script que acabei de fazer [1] tenho um arquivo de texto que é uma lista de nomes de usuário (um por linha). E quero checar se eles existem no sistema. Fiz deste jeito:

while IFS= read i; do
grep -qm1 "^$i:" /etc/passwd && echo "$i matches with an existent user. Be careful!"
done < "$outfile"

Mas este "$outfile" é muito grande. Milhares de linhas e demora um pouco. Alguma ideia pra otimizar?

Grato e feliz natal! :)

[1] https://gist.github.com/merces/0a4d2272d79d00cc0fe1

Att,

Fernando Mercês
Linux Registered User #432779
www.mentebinaria.com.br
------------------------------------
"Ninguém pode ser escravo de sua identidade; quando surge uma possibilidade de mudança é preciso mudar". (Elliot Gould)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]