Como pesquisar em arquivos .ODT, com o comando grep

Infelizmente, o comando grep não consegue enxergar o conteúdo de arquivos .odt, bem como muitos outros arquivos que não sejam puro texto.
Arquivos binários, como é o caso, não são transparentes para o uso do grep.

Neste texto, vou mostrar como fazer a conversão do seu arquivo .odt e, durante o processo, o grep captura o conteúdo e faz a busca pelas strings que você sugere, na linha de comando.
Para isto, o utilitário odt2txt faz a conversão do .odt e repassa o resultado ao comando grep.
A sintaxe é assim:

odt2txt --stdout nome-do-arquivo.odt | grep -i string-a-ser-pesquisada

Veja um exemplo:


odt2txt --stdout Documentos/Linux\ Cloud.odt | grep -i linux

A Evolução do GNU/Linux
Distribuições GNU/Linux
Certificação Linux
Mercado Linux
Conhecendo a Arquitetura do Sistema Linux
Linux Inside: Instalação Desktop Debian e CentOS

Com a opção ‘–stdout’, o utilitário odt2txt desvia o resultado para a saída padrão do sistema.
Em seguida, o grep é chamado para interceptar o resultado, no modo texto e exibir as linhas que contém a cadeia de caracteres solicitada.

Leia mais sobre o comando grep.

Use o utilitário tr para substituir caracteres dentro de arquivos texto

O tr, no Linux, é usado para traduzir ou remover caracteres dentro de arquivos de sequências de texto.
Pode ser usado também para fazer substituições de caracteres, como veremos nos exemplos abaixo — que fazem uso também do utilitário cat.
Para os meus exemplos, vou criar um arquivo a partir do /etc/fstab:


cp /etc/fstab teste.txt

Agora tenho um lugar mais seguro para brincar…
Este é o conteúdo original dele:


cat teste.txt 

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
#                
# / was on /dev/sdb1 during installation
UUID=ae9797c5-677a-400d-aad7-4fbe960b94ad /               btrfs   defaults        0       0
# /home was on /dev/sda1 during installation
UUID=d44c3678-1743-4c24-85b1-a6f437f4bb87 /home           btrfs   defaults        0       0
# o swap fica em /dev/sdb2 /dev/sda2 
/dev/sdb2   swap    swap    defaults    0   0
/dev/sda2   swap    swap    defaults    0   0

Como substituir espaços por tabulações dentro de um arquivo texto

Com o pipe |, é possível passar o conteúdo de um arquivo texto para o tr, que realiza o procedimento, no caso abaixo, de substituir os espaços por tabulações:


cat teste.txt | tr ':[space]:' '\t' > teste-a.txt

Use o cat, para ver o resultado no arquivo teste-a.txt:


cat teste-a.txt

Se você prefere substituir cada espaço por 2 espaços, troque o ‘\t’ por ‘ ‘ (com 2 espaços dentro):


cat teste.txt | tr ':[space]:' '  ' > teste-a.txt

Experimente usar ‘ ‘ (com espaços de verdade dentro), em vez de ‘:[space]:’, para ver a diferença.

Como converter todos os caracteres minúsculos para maiúsculos e vice-versa, dentro de um texto

Com o comando abaixo, vamos converter o conteúdo do arquivo teste.txt de minúsculas para maiúsculas:


cat teste.txt | tr a-z A-Z > teste-b.txt

Veja o meu resultado:


cat teste-b.txt 

# /ETC/FSTAB: STATIC FILE SYSTEM INFORMATION.
#
# USE 'BLKID' TO PRINT THE UNIVERSALLY UNIQUE IDENTIFIER FOR A
# DEVICE; THIS MAY BE USED WITH UUID= AS A MORE ROBUST WAY TO NAME DEVICES
# THAT WORKS EVEN IF DISKS ARE ADDED AND REMOVED. SEE FSTAB(5).
#
#                
# / WAS ON /DEV/SDB1 DURING INSTALLATION
UUID=AE9797C5-677A-400D-AAD7-4FBE960B94AD /               BTRFS   DEFAULTS        0       0
# /HOME WAS ON /DEV/SDA1 DURING INSTALLATION
UUID=D44C3678-1743-4C24-85B1-A6F437F4BB87 /HOME           BTRFS   DEFAULTS        0       0
# O SWAP FICA EM /DEV/SDB2 /DEV/SDA2 
/DEV/SDB2   SWAP    SWAP    DEFAULTS    0   0
/DEV/SDA2   SWAP    SWAP    DEFAULTS    0   0

Se você tem alguma sugestão de uso do tr, deixe a gente saber, nos comentários 😉

Conheça estes 7 motivos para abandonar o comando grep e passar a usar o ack.

Tecnicamente, o ack foi projetado como ferramenta de busca dentro de arquivos texto — tendo como público-alvo os programadores.
Entre estes, o utilitário é mais eficiente do que o comando grep.
Neste texto, vou mostrar algumas vantagens de uso do ack e como instalar a ferramenta no Linux (caso ela já não esteja instalada aí).
Entre as vantagens de usar o ack — para fazer pesquisa dentro do código fonte — a documentação oficial cita:

  1. É rápido — por que se restringe a strings que “façam sentido” retornar. As expressões regulares em Perl tem alto índice de otimização.
  2. É portável — por ser escrito em Perl e não ter outras dependências além do Perl 5, pode rodar no Windows, MAC, UNIX e nos vários sabores do BSD e do Linux.
  3. Ignora automaticamente diretórios irrelevantes para a sua busca — a recursividade é seu comportamento padrão, mas ele ignora arquivos .git, .svn e diretórios CVS e VCS. Lógico que você pode mudar isto manualmente.
    Como exemplo da praticidade, a documentação compara os dois comandos de busca, a seguir, que tem resultados semelhantes:

    grep pattern $(find . -type f | grep -v '\.git')
    

    ou

    ack pattern
    

    Qual você prefere?

  4. Melhores resultados — como ele prioriza arquivos de código fonte, você obtém menos resultados irrelevantes. Ele pula até arquivos de backup.
  5. Separa fácil os arquivos — para quem tem um projeto envolvendo mais de uma linguagem de programação (muito comum entre web developers).
    É fácil adicionar –python, para restringir as buscas dentro de arquivos da linguagem Python, ou –nohtml evitar arquivos HTML.

    O ack tem detecção de tipos de arquivos, muito além da leitura da extensão do nome.

    Veja outra comparação entre comandos grep e ack, para realizar buscas dentro de arquivos Perl:

    grep pattern $(find . -name '*.pl' -or -name '*.pm' -or -name '*.pod' | grep -v .git)
    
    ack --perl pattern 
    

    Novamente, qual dos dois comandos, acima, você prefere usar?
    Note que o sucesso do grep, no primeiro exemplo, depende do uso do comando find (leia mais sobre ele aqui). O ack é visivelmente mais eficiente, neste caso.

  6. Listas de arquivos — podem ser criadas, antes mesmo de qualquer busca.
    Esta utilidade vai agradar até quem não é programador. Com o comando, abaixo, o ack relaciona todos os arquivos da linguagem PHP, em um diretório, recursivamente:

    ack -f --php
    

    Você gastaria um pouco mais de seus dedos para realizar esta tarefa com o find…

  7. O ack tem highlighting, que permite realçar palavras-chave nos resultados das buscas.

linux terminal ack command
Por fim, A palavra “ack” é menor do que “grep”, o que te poupa alguns preciosos milésimos de segundos na digitação a cada vez que precisar realizar uma busca.

Como instalar o ack no sistema

O ack está disponível nos repositórios das principais distribuições (se não todas) Linux e UNIX (BSD).
Infelizmente, no momento em que escrevo este texto, ele ainda não faz parte do conjunto de programas utilitários padrão, que já “estão lá”, logo após a instalação.
Contudo, ele é super fácil de instalar.
Quem usa o Debian, pode usar o apt, para fazer o trabalho:

sudo apt update
sudo apt install ack

No Ubuntu 16.04 LTS, o nome do pacote (transitório) é ack-grep. Nas futuras atualizações ele deve ser renomeado para apenas “ack”.
O pessoal do Fedora, pode instalar com o dnf:

sudo dnf install ack

No FreeBSD, use os ports e instale o pacote p5-ack.
Leia outros textos sobre o assunto, tocando ou clicando na tag ack, para conhecer melhor a ferramenta.
Além disto, não esqueça de compartilhar o texto nas redes sociais. 😉

Referências

https://beyondgrep.com/.
http://www.activestate.com/blog/2016/12/grep-losing-its-grip.

Como manipular valores de data e hora como números no MySQL

Transformar strings contendo valores temporais (de data e/ou hora) pode ser útil quando se deseja realizar operações aritméticas, envolvendo-os. Os valores podem ser convertidos de volta para data e/ou hora, com relativa facilidade.
O processo consiste, basicamente em adicionar o valor zero ou usar o valor temporal em um contexto numérico — o MySQL irá entender que aquele valor é um número.
Veja um exemplo:

SELECT CURRENT_DATE() AS Hoje, CURRENT_DATE()+0 AS "Hoje, como núm.";
+------------+------------------+
| Hoje       | Hoje, como núm.  |
+------------+------------------+
| 2015-07-14 |         20150714 |
+------------+------------------+

CURRENT_DATE() é a função responsável por retornar a data atual. Como você pode ver, no exemplo acima, ao adicionar 0 (zero), o valor passou de data para número.
Na condição de valor numérico, é possível realizar todas as operações aritméticas e, em seguida, voltar (nem sempre…) a valor temporal.
Veja outro exemplo:

SELECT DATE(DataCadastroCliente) AS Cadastro, DATE(DataCadastroCliente)+0 AS "Número", YEAR(DataCadastroCliente)+1 AS "Ano +1" FROM CadastroClientes LIMIT 10;
+------------+----------+--------+
| Cadastro   | Número   | Ano +1 |
+------------+----------+--------+
| 2016-03-29 | 20160329 |   2017 |
| 2015-06-20 | 20150620 |   2016 |
| 2013-03-29 | 20130329 |   2014 |
| 2015-11-29 | 20151129 |   2016 |
| 2016-06-11 | 20160611 |   2017 |
| 2014-06-14 | 20140614 |   2015 |
| 2015-08-31 | 20150831 |   2016 |
| 2012-08-28 | 20120828 |   2013 |
| 2013-05-29 | 20130529 |   2014 |
| 2013-06-03 | 20130603 |   2014 |
+------------+----------+--------+

mysql-convert-datetime-to-number
Fique atento.
Ao adicionar 0 (ou qualquer outro valor numérico) a um valor temporal, este deixa de ter valor temporal e passa a ser uma simples string numérica.
Essencialmente, você deve esperar, como resultado, uma string sem os delimitadores de data.
Mas apenas o primeiro componente da data ou da hora será interpretado como numérico, durante a conversão. Veja por si só:

SELECT '2016-01-01'+0, '2016-01-01 15:45:25'+0, '15:45:25'+0;
+----------------+-------------------------+--------------+
| '2016-01-01'+0 | '2016-01-01 15:45:25'+0 | '15:45:25'+0 |
+----------------+-------------------------+--------------+
|           2016 |                    2016 |           15 |
+----------------+-------------------------+--------------+

Para resolver isto, use as funções SEC_TO_TIME() e TIME_TO_SEC().

Como decompor ou combinar strings no MySQL

Saiba como quebrar ou separar partes de uma cadeia de caracteres para obter uma substring ou como combinar mais de uma string para obter uma cadeia maior.
Partes deste assunto, já foram abordadas em outros artigos no site — portanto, se quiser saber um pouco mais sobre algum quesito, clique nos links correspondentes, ao longo do texto.
Outumn trees over lake and mysql logo
A solução para separar trechos de uma cadeia de caracteres é usar uma função de extração de substrings.
Para obter o efeito contrário, use a função CONCAT(). Com esta função, é possível juntar cadeias de caracteres e criar novas formatações para diversos tipos de dados.

Funções para extração de caracteres ou strings no MySQL

A versão 5.7 do MySqL tem mais de 50 funções para lidar com strings.
Ao aprender a lidar com algumas, você estará apto(a) a lidar com todas.
Nos primeiros exemplos deste post, vou mostrar o funcionamento de 3, destas funções: LEFT(), MID() e RIGHT().
Elas servem para extrair substrings de uma cadeia de caracteres da parte à esquerda, do meio e da direita, respectivamente.
Neste primeiro exemplo, vou mostrar como retirar 2 caracteres destas partes da relação de cidades, da tabela ClientesCidades.

SELECT CidadeCliente, LEFT(CidadeCliente, 2) AS "Primeira parte", MID(CidadeCliente, 3, 2) AS "Parte do meio", RIGHT(CidadeCliente, 2) AS "Última parte" FROM ClientesCidades LIMIT 5;
+---------------+----------------+---------------+---------------+
| CidadeCliente | Primeira parte | Parte do meio | Última parte  |
+---------------+----------------+---------------+---------------+
| Buti          | Bu             | ti            | ti            |
| Whitehorse    | Wh             | it            | se            |
| Bertiolo      | Be             | rt            | lo            |
| Exeter        | Ex             | et            | er            |
| Fortune       | Fo             | rt            | ne            |
+---------------+----------------+---------------+---------------+
5 rows in set (0.00 sec)

A função LEFT() retorna o número especificado e caracteres de dentro de uma string. Veja um outro exemplo:

SELECT LEFT('GNU/Linux',3);
+----------------------+
| LEFT('GNU/Linux', 3) |
+----------------------+
| GNU                  |
+----------------------+
1 row in set (0.00 sec)

Com a função RIGHT(), tudo funciona do mesmo jeito. Só que na direção inversa:

SELECT RIGHT('GNU/Linux', 5);
+-----------------------+
| RIGHT('GNU/Linux', 5) |
+-----------------------+
| Linux                 |
+-----------------------+
1 row in set (0.00 sec)

A função MID() é sinônima de SUBSTRING(). Ela pede que você informe em que posição, no meio da string, a contagem deve começar:

SELECT MID('Debian GNU/Linux', 8, 3);

A declaração pede para “retirar 3 caracteres, a partir da 8a. posição”:

+-------------------------------+
| MID('Debian GNU/Linux', 8, 3) |
+-------------------------------+
| GNU                           |
+-------------------------------+
1 row in set (0.00 sec)

Mysql string functions
Clique para ampliar.

A função SUBSTR() tem funcionamento semelhante, de acordo com a documentação do MySQL (veja link ao final do texto).
A função LEFT() pode ser usada para encontrar todos os nomes, dentro de uma tabela, que comecem com uma determinada letra do alfabeto:

SELECT LEFT(nomeCliente,6) FROM ClientesCidades WHERE LEFT(nomeCliente,1)="W";
+---------------------+
| LEFT(nomeCliente,6) |
+---------------------+
| Winter              |
| Willow              |
| Wilma               |
| Willow              |
| Willow              |
| Wyomin              |
| Willa               |
| Wynne               |
+---------------------+
8 rows in set (0.00 sec)

Veja como obter uma relação de nomes de clientes cujos nomes começam com W, X, Y ou Z (as últimas letras do alfabeto em inglês), em ordem alfabética:

SELECT nomeCliente AS "Clientes de W a Z" FROM ClientesCidades WHERE LEFT(nomeCliente,1)>="W" ORDER BY nomeCliente;
+-------------------+
| Clientes de W a Z |
+-------------------+
| Willa Kerr        |
| Willow Graham     |
| Willow Mitchell   |
| Willow Simmons    |
| Wilma Hill        |
| Winter Fischer    |
| Wynne Bauer       |
| Wyoming Graham    |
| Xantha Wise       |
| Xyla Dennis       |
| Yen Espinoza      |
| Yetta Wood        |
| Yoshi Nguyen      |
| Yvonne Wilcox     |
| Zelenia Brady     |
| Zelenia Moss      |
| Zenia Carr        |
| Zephr Webb        |
| Zia Fernandez     |
+-------------------+
19 rows in set (0.00 sec)

Você pode usar a função CONCAT(), para construir novas strings, usando os nomes dos clientes:

SELECT CONCAT("A Cliente ",nomeCliente, " mora em ",cidadeCliente) AS "Clientes de Y a Z" FROM ClientesCidades WHERE LEFT(nomeCliente,1)>="Y" ORDER BY nomeCliente;

Veja o meu resultado:

+------------------------------------------------+
| Clientes de Y a Z                              |
+------------------------------------------------+
| A Cliente Yen Espinoza mora em Pramaggiore     |
| A Cliente Yetta Wood mora em Doues             |
| A Cliente Yoshi Nguyen mora em Daiano          |
| A Cliente Yvonne Wilcox mora em Sherbrooke     |
| A Cliente Zelenia Brady mora em Modena         |
| A Cliente Zelenia Moss mora em Elx             |
| A Cliente Zenia Carr mora em Wernigerode       |
| A Cliente Zephr Webb mora em Recanati          |
| A Cliente Zia Fernandez mora em Market Drayton |
+------------------------------------------------+
9 rows in set (0.00 sec)

Como você pode ver, dá pra brincar bastante com as funções de manipulação de strings. Faça as suas experiências!
Você pode usar a função CONCAT(), para alterar os valores de uma coluna.
No exemplo, abaixo, acrescentamos a string “_abc” aos nomes dos clientes da tabela ClientesCidades:

UPDATE ClientesCidades SET NomeCliente = CONCAT(NomeCliente,"_abc");
SELECT NomeCliente FROM ClientesCidades LIMIT 5;
+---------------------+
| NomeCliente         |
+---------------------+
| Dara Chase_abc      |
| Hanae Kane_abc      |
| Jaden Moon_abc      |
| Cathleen Harvey_abc |
| Marcia Cole_abc     |
+---------------------+
5 rows in set (0.00 sec)

Para desfazer esta bagunça, você pode usar a função LENGTH() para posicionar a função LEFT() antes destes 4 caracteres e gravar o resultado:

UPDATE ClientesCidades SET NomeCliente = LEFT(NomeCliente, LENGTH(NomeCliente)-4);

E veja como tudo volta ao normal:

SELECT NomeCliente FROM ClientesCidades LIMIT 5;
+-----------------+
| NomeCliente     |
+-----------------+
| Dara Chase      |
| Hanae Kane      |
| Jaden Moon      |
| Cathleen Harvey |
| Marcia Cole     |
+-----------------+
5 rows in set (0.00 sec)

Referências: