Fontes de sed, grep, tr, ... em C onde encontrar?

1. Fontes de sed, grep, tr, ... em C onde encontrar?

Fernando Ventura Pires Junior
fventurajr

(usa Ubuntu)

Enviado em 16/11/2019 - 08:04h

Saberiam me dizer se em alguma pasta do Linux há os fontes das ferramentas do bash, que imagino, tenham sido escritas em C?

Tenho o livro do Aurelio Vargas, que considero o melhor livro de expressões regulares e me decepcionei com a sua implementação em C. Como o Linux, pelo menos em boa parte foi escrito em C(ou C++) acredito que estudando os fontes posso entender como usar as REGEX em C.


  


2. Re: Fontes de sed, grep, tr, ... em C onde encontrar?

Paulo
paulo1205

(usa Ubuntu)

Enviado em 17/11/2019 - 00:04h

fventurajr escreveu:

Saberiam me dizer se em alguma pasta do Linux há os fontes das ferramentas do bash, que imagino, tenham sido escritas em C?


apt-get source coreuils 


Se isso não funcionar, baixe diretamente de ftp://ftp.gnu.org/gnu/coreutils/.

Tenho o livro do Aurelio Vargas, que considero o melhor livro de expressões regulares e me decepcionei com a sua implementação em C. Como o Linux, pelo menos em boa parte foi escrito em C(ou C++) acredito que estudando os fontes posso entender como usar as REGEX em C.


Não tenho o livro que você menciona. O que você quer dizer com “sua implementação em C”? A forma como se usam expressões regulares padronizadas pelo POSIX (i.e. as formas como as funções regcomp(), regexec() e regfree() e seus resultados são usados) ou detalhes internos da implementação dessa biblioteca?


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)


3. Re: Fontes de sed, grep, tr, ... em C onde encontrar?

Fernando Ventura Pires Junior
fventurajr

(usa Ubuntu)

Enviado em 17/11/2019 - 06:41h

Obrigado pela pronta resposta. Segundo esse livro, é um pouco complicado escrever um programa em C que faça uso de expressões regulares. Tanto que pensei em usar o C++, que parece ser bem mais simples.

Não estou com o livro no momento, mas lembro que primeiro ele compila a expressão regular e pode resultar em erro. Caso a compilação execute sem problemas faz se a busca e obtém-se o resultado, mas aí ele faz uma estrutura de repetição para conseguir ver os trechos onde houve correspondência.

A minha ideia é fazer um programa em Perl para varrendo um log dos acessos ao sistemas intranet no trabalho e capturar os sistemas de interesse e formatá-lo em formato csv para poder processá-lo em planilhas. Caso fique lento por Perl ser interpretado, reescreveria o código em C ou C++.


4. Re: Fontes de sed, grep, tr, ... em C onde encontrar?

Paulo
paulo1205

(usa Ubuntu)

Enviado em 17/11/2019 - 16:42h

Bom, o C é uma linguagem simples sintaticamente e em termos das construções que oferece. Essa simplicidade essencial se reflete no poder de expressividade que está à disposição dos programadores, que não é muito grande.

Porém, há de ter em mente que o propósito do C, originalmente, não era mesmo do de ser uma linguagem expressiva, mas de ser uma ferramenta versátil e relativamente eficiente para construir ferramentas em nível de sistema.

Quando se dispõe apenas de comandos de controle de fluxo, variáveis de tipos simples e exatamente três formas de agregar tais variáveis (arrays, struct e union) e de funções, com ponteiros explicitamente passando de um lado a outro, não se pode querer que a forma de trabalhar com expressões regulares seja tão simples como é em Perl, por exemplo, que, por sinal, foi concebida e construída com o propósito específico de processamento de textos através de expressões regulares.

A expressividade muitas vezes esconde a complexidade. Por exemplo, o seguinte bloco em Perl, com suas poucas linhas, tem exatamente a mesma complexidade interna que o equivalente em C.
# Perl: Faz o parsing de uma linha válida no formato de /etc/passwd.
if($str=~/^([^#+-]?[^:]+):([^:]):([+-]?\d+):([+-]?\d+):([^:]*):([^:]*):([^:]*)$/){
($username, $password, $uid, $gid, $gecos, $homedir, $shell)=($1, $2, 0+$3, 0+$4, $5, $6, $7);
}

/* C: Faz o parsing de uma linha válida no formato de /etc/passwd. */
// (Supõe que os tipos de str, username, password, gecos, home dir e shell sejam char *
// e os de uid e gid sejam uid_t e gid_t, respectivamente).
regex_t re;
if(regcomp(&re, "^([^#+-]?[^:]+):([^:]):([+-]?[[:digit:]]+):([+-]?[[:digit:]]+):([^:]*):([^:]*):([^:]*)$", REG_EXTENDED)==0){
regmatch_t parts[8];
if(regexec(&re, str, 8, parts, 0)==0){
char *part_str[8]={NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
for(int p=0; p<8; ++p){
ssize_t len=parts[p].rm_eo-parts[p].rm_so;
if(parts[p].rm_so>=0 && len>0){
if((parts_str[p]=malloc(1+len))!=NULL){
strncpy(parts_str[p], str+parts[p].rm_so, len);
parts_tr[p][len]='\0';
}
else{
perror("Não foi possível alocar memória para armazenar parte da expressão regular");
abort();
}
}
else
parts_str[p]=strdup("");
}
username=strdup(parts_str[1]);
password=strdup(parts_str[2]);
uid=atoll(parts_str[3]);
gid=atoll(parts_str[4]);
gecos=strdup(parts_str[5]);
homedir=strdup(parts_str[6]);
shell=strdup(parts_str[7]);
for(int p=0; p<8; ++p)
free(parts_str[p]);
}
regfree(&re);
}


Em C++, cujas classes dão um poder de expressividade maior do que o do C, a coisa fica um pouco mais limpa visivelmente, mas tem um custo perceptível no tamanho do código executável gerado porque, além das expressões regulares em si, há um peso decorrente da incorporação das funcionalidades associadas de strings e de tratamento de exceções, que o C não tem. Nada vem de graça. (O Perl, aliás, traz consigo o peso ainda maior do que apenas strings e exceções, pois carrega junto com cada programa o peso de todo o interpretador da linguagem, já que os programas são interpretados a cada execução, e o interpretador não tem como saber de antemão quais recursos cada programa vai usar ou deixar de usar.)
// C++: Parsing de uma linha no formato do /etc/passwd usando a classe std::regex.
// (Supõe que os tipos de str, username, password, gecos, home dir e shell sejam std::string
// e os de uid e gid sejam uid_t e gid_t, respectivamente).
std::smatch parts;
if(regex_match(str, parts, std::regex("^([^#+-]?[^:]+):([^:]):([+-]?\\d+):([+-]?\\d+):([^:]*):([^:]*):([^:]*)$"))){
username=parts[1];
password=parts[2];
uid=stoll(parts[3]);
gid=stoll(parts[4]);
gecos=parts[5];
homedir=parts[6];
shell=parts[7];
}


Note que, nos casos acima (inclusive o de Perl, em versões antigas), as expressões regulares são reinterpretadas e transformadas para um formato interno cada vez que o fluxo de execução passar pelas linhas em que elas aparecem. Se os blocos acima forem executados dentro de laços de repetição, o ideal seria que essas transformações para formatos internos (a sintaxe “/.../” do Perl, o regcomp() do C/POSIX ou o construtor de std::regex do C++) fossem feitas fora dos laços de repetição, e apenas a operação de match (“=~”, regexec() ou regex_match()) ficassem dentro do laço de repetição.


Com relação a sua preocupação quanto a velocidade, se você vai apenas ler o rquivo de logs e extrair partes que lhe interessam para um processamento simples, provavelmente Perl terá desempenho suficiente. Só seria interessante partir para algo mais especializado se você tiver boa parte do processamento fora da parte de extração de dados. (Mas você pode fazer protótipos para valiar o desempenho relativo, se quiser.)

----

NOTA: Não testei nenhum dos código acima, pois os escrevi diretamente na postagem no fórum. Pode ser que contenham erros.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)


5. Re: Fontes de sed, grep, tr, ... em C onde encontrar?

Fernando Ventura Pires Junior
fventurajr

(usa Ubuntu)

Enviado em 17/11/2019 - 19:51h

Obrigado novamente.

Antes do Perl eu ainda tentaria outros caminhos:

1- Usar comandos do Bash: grep, sed, ...
2- Sites que permitem filtrar por REGEX como regexpal.com, regextester.com, ...
3- Importaria o log para o Excel, por exemplo, e usaria alguma fórmula do vba para filtrar o que eu desejo.
...
Perl
C++

Agora vou poder usar o C++, embora como você disse, o Perl deve dar conta, embora seja uma linguagem interpretada.


6. Re: Fontes de sed, grep, tr, ... em C onde encontrar?

Paulo
paulo1205

(usa Ubuntu)

Enviado em 17/11/2019 - 21:35h

fventurajr escreveu:

Obrigado novamente.

Antes do Perl eu ainda tentaria outros caminhos:

1- Usar comandos do Bash: grep, sed, ...


Não recomendo, a não ser que você faça com muito cuidado. O motivo é que a invocação de comandos externos (que não são do bash) é custosa, especialmente se você os invocar de dentro de laços de repetição (além do custo de compilação das expressões regulares, sobre o qual falei acima, ainda existe o custo de criação de processos, execução de comandos, passagem de dados entre processos e finalização de processos com liberação de recursos).

2- Sites que permitem filtrar por REGEX como regexpal.com, regextester.com, ...


Não conheço. Mas você tem de ver se é aceitável enviar seus logs para fontes externas. Dependendo do que seja, isso pode ser perigoso, ou mesmo proibido. Então, cuidado.

3- Importaria o log para o Excel, por exemplo, e usaria alguma fórmula do vba para filtrar o que eu desejo.


Possível. A forma conservadora de fazer isso seria aplicar o filtro durante a importação, em lugar de gastar memória desnecessariamente para importar todo o log, e depois eliminar o que não se quer.

...
Perl
C++

Agora vou poder usar o C++, embora como você disse, o Perl deve dar conta, embora seja uma linguagem interpretada.


Se for, como parece, um filtro simples, deve, sim, dar conta muito bem.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts