Português do Brasil English
Devin no Facebook  Devin no Twitter  RSS do Site 
Linux    

Comandos de Tratamento de Texto


Comentários  36
Visualizações  
99.318

sort – Ordena um arquivo alfabeticamente

Sintaxe: $ sort <arquivo>

Quando temos um arquivo com várias linhas, por exemplo, um arquivo de nomes de usuários, o sort pode servir para organizar este arquivo. Exemplo:

$ cat texto
Kioshi
Hugo
Adriana
Eitch
Danilo

$ sort texto
Adriana
Danilo
Eitch
Hugo
Kioshi

Os nomes foram organizados e o resultado é jogado na tela. Ordenando o arquivo e escrevendo o resultado em outro arquivo:

$ sort texto > texto_organizado

Podemos também ordenar de forma inversa, com o parâmetro -r:

$ sort -r texto
Kioshi
Hugo
Eitch
Danilo
Adriana

uniq – Elimina linhas repetidas

Sintaxe: $ uniq <arquivo>

Muitas vezes um arquivo de configuração tem várias linhas em branco, ou um arquivo texto tem várias linhas iguais que queremos eliminar. O uniq elimina as ocorrências de linhas repetidas, lembrando que as linhas iguais devem estar uma depois da outra para serem consideradas repetidas.

Exemplo:

$ cat texto
Kioshi
Hugo
Hugo
Adriana
Eitch
Danilo
Kioshi
Kioshi

$ uniq texto
Kioshi
Hugo
Adriana
Eitch
Danilo
Kioshi

Note que apesar do uniq ter eliminado as linhas duplicadas (Hugo e Kioshi do final do arquivo), o comando mesmo assim deixou a palavra Kioshi duas vezes no arquivo, pois eles estão em diferentes localizações. Para resolver isto, combinamos com o sort:

$ sort texto | uniq
Adriana
Danilo
Eitch
Hugo
Kioshi

Desta forma, o sort primeiro ordenou as linhas, deixando as repetidas uma depois da outra, fazendo com que o uniq eliminasse essas linhas duplicadas.

grep – Procura texto e expressões dentro de um arquivo

Sintaxe: $ grep <padrão> <arquivo1> [arquivo2] [arquivo3] ...

Quando temos arquivos com muitas informações, mas queremos apenas extrair algo bem específico do conteúdo, utilizamos o grep. Ele procura por algum texto (um padrão) dentro de arquivos, retornando a linha correspondente ao desejado.

Por exemplo, quero identificar se existe o nome Hugo no arquivo de palavras (dicionário) do sistema:

$ grep Hugo /usr/share/dict/words
Hugo
Hugo's

Por padrão, o grep diferencia maiúsculas e minúsculas, então se fizermos o comando anterior utilizando a palavra hugo em minúsculo, o grep não iria achar nada.

Para fazer uma pesquisa sem diferenciar maiúsculas de minúsculas, utilizamos o parâmetro -i:

$ grep -i ROOT /etc/passwd
root:x:0:0:root:/root:/bin/bash

Mostramos que o usuário root existe no sistema, pois ele está no arquivo /etc/passwd.

Para identificar em que linha do arquivo o grep achou o texto, utilizamos o parâmetro -n:

$ grep -in servername /etc/httpd/conf/httpd.conf
130:ServerName www.devin.com.br

O grep achou, na linha 130, a palavra servername e imprimiu na tela toda a linha.

Podemos também especificar para o grep procurar recursivamente, ou seja, em um diretório e todos os seus arquivos e sub-diretórios, utilizando o parâmetro -r:

$ grep -ri backup /home/coletivo

Para inverter o que o grep mostra, ou seja, imprimir as linhas que não contém o texto, basta utilizar o parâmetro -v:

$ grep -v root /etc/passwd
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
...corte...

O grep mostrou todas as linhas dos usuários do sistema, menos a do usuário root.

Também podemos usar expressões regulares para procurar certos padrões de texto em um arquivo. Por exemplo, mostrando todas as linhas de um arquivo que não começam com o caracter # (ou seja, linhas que não são comentários):

$ grep -v "^#" /etc/apache2/apache2.conf
ServerRoot "/etc/apache2"
LockFile /var/lock/apache2/accept.lock
PidFile ${APACHE_PID_FILE}
Timeout 300
KeepAlive On
...corte...

Se verificarmos o arquivo, veremos que além destas linhas, há uma série de comentários no arquivo, mas que não foram mostradas pelo grep.

paste – Combina arquivos em um só

Sintaxe: $ paste <arquivo1> <arquivo2> [arquivo3] ...

Com este comando podemos unir vários arquivos em um só, em formato de tabela, tornando o resultado algo parecido com uma planilha. Por exemplo, temos dois arquivos:

$ cat nomes
Coletivo Digital
Hugo Cisneiros (Eitch)
Linux
Tutorial

$ cat enderecos
[email protected]
[email protected]
www.kernel.org
www.google.com.br

Juntando os dois arquivos com o paste:

$ paste nomes enderecos
Coletivo Digital        [email protected]
Hugo Cisneiros (Eitch)  [email protected]
Linux   www.kernel.org
Tutorial        www.google.com.br

O paste juntou as linhas, separando os campos com TAB.

cut – Separa um arquivo por campos e imprime apenas partes especificadas

Sintaxe: $ cut [opções] <arquivo1>

Bom para quando quisermos isolar partes de linhas de um arquivo de configuração ou de arquivos de dados tabulados. Basicamente, o parâmetro -d especifica o delimitador de campos e o -f indica qual campo imprimir como resultado. Exemplo:

$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
...corte...

$ cut -d ":" -f 1 /etc/passwd
root
daemon
...corte...

Utilizamos como delimitador o caracter “:” (dois pontos), que é o que separa os campos do arquivo de usuários do sistema /etc/passwd. Informamos também para o cut jogar como resultado apenas o campo de número um.

No parâmetro -f, podemos também especificar faixas de campos, ao invés de apenas um:

$ cut -d ":" -f 1,7 /etc/passwd
root:/bin/bash
daemon:/bin/sh
...corte...

Desta vez ele retornou os campos 1 e 7, que são respectivamente o usuário e a shell do usuário. Outro exemplo:

$ cut -d ":" -f 1-4,7 /etc/passwd
root:x:0:0:/bin/bash
daemon:x:1:1:/bin/sh
...corte...

Desta vez ele imprimiu os campos de 1 a 4 (1, 2, 3 e 4), depois o campo 7.

tr – Transforma caracteres

Sintaxe: $ tr <origem> <destino>

Transforma caracteres em outros caracteres (ou os remove). Com o tr conseguimos fazer essa substituição caracter por caracter, mas não podemos utilizá-lo com um arquivo, mas apenas combinando com outros comandos.

Por exemplo, quero transformar todos os caracteres do arquivo nomes para maiúsculo:

$ cat nomes
Coletivo Digital
Hugo Cisneiros (Eitch)
Linux
Tutorial

$ cat nomes | tr [:lower:] [:upper:]
COLETIVO DIGITAL
HUGO CISNEIROS (EITCH)
LINUX
TUTORIAL

sed – Filtragem e Transformação de Conteúdo

Sintaxe: $ sed <comando/expressão> <arquivo>

O sed é um poderoso processador de texto que dentre muitas de suas ações, pode substituir ocorrências de texto por outros textos. Por exemplo, temos o texto:

$ cat texto
Eu adoro música. Acho que sem música eu não seria nada, ficaria completamente
triste, deprimido. Também acredito que todo ser humano precisa de música, afinal
não importa o seu sabor, é sempre bom!

Agora vamos substituir a palavra música por Linux:

$ sed "s/música/Linux/g" texto
Eu adoro Linux. Acho que sem Linux eu não seria nada, ficaria completamente
triste, deprimido. Também acredito que todo ser humano precisa de Linux, afinal
não importa o seu sabor, é sempre bom!

Neste exemplo, a primeira parte do comando (/s) disse ao sed para procurar as ocorrências de música e transformá-las para Linux. A última letra (g) diz para substituir todas as ocorrências da linha.

Você também pode preferir substituir o texto e alterar o arquivo diretamente (ao invés de aparecer apenas na tela). Para fazer isso, use o parâmetro -i:

$ sed -i "s/música/Linux/g" texto

Cuidado: O -i vai sobrescrever o arquivo original e você não vai ter um Undo (também conhecido como Ctrl+Z) para te ajudar! Mas combinando o -i com uma extensão, ele cria um backup pra você antes de substituir:

$ sed -i.backup "s/música/Linux/g" texto

Com isso ele vai criar o arquivo texto.backup com o texto original, e o o arquivo texto estará modificado.

Este é um dos usos mais comuns do sed, apesar dele poder fazer muito mais.

99.318

Comentários  36
Visualizações  
99.318


TagsLeia também

Apaixonado por Linux e administração de sistemas. Viciado em Internet, servidores, e em passar conhecimento. Idealizador do Devin, tem como meta aprender e ensinar muito Linux, o que ele vem fazendo desde 1997 :-)


Leia também



Comentários

36 respostas para “Comandos de Tratamento de Texto”

  1. Fabiano disse:

    Sobre o sort, vale lembrar que o comando possui a opção -o, que permite indicar um arquivo de saída, que inclusive pode ser o mesmo arquivo de entrada, simplificando assim os scripts e operações do dia-a-dia.

  2. Rodrigo Cesar disse:

    Podia Falar um pouco mais sobre o comando grep

  3. @Rodrigo:

    Sugestão anotada, obrigado!

  4. vandocouto disse:

    Muito obrigado! parabéns me ajudou bastante mesmo.

    Abraços

    vandocouto

  5. andluve disse:

    Legal demais

  6. Odlanier disse:

    Muito bom! Parabéns pelas dicas, excelente texto. xD

  7. Hugo Luiz disse:

    Show… vlw mesmo pelo assunto…

  8. […] Devin Share this:TwitterFacebookGostar disso:GostoSeja o primeiro a gostar disso post. CategoriasLinux […]

  9. escriba666 disse:

    muito bom

    valeu, copiado e sempre estudado

  10. Valeria disse:

    Boa Noite!, chamo-me Sara estudo Ergonomia e adoeri imenso da tua pe1gina! Muito bonita sim senhora!Adequa-se muito bem em tudo aquilo que aqui observei.Existe por vezes he1 tanto que regidir nos blogues!Nada nada mais intrigante do que implementar a nossa marca online!Bye Bye

  11. Excelentes dicas, o comando cut eu não conhecia, uso bastante o sed. Bom saber que tem alternativas e comandos que ainda desconhecemos. Obrigado por compartilhar conhecimento.

  12. Gilson disse:

    Muito bom o artigo, me deu uma luz no meu problema .

  13. Narviksw disse:

    Bom dia,

    Conforme o texto :

    Eu adoro música. Acho que sem música eu não seria nada, ficaria completamente
    triste, deprimido. Também acredito que todo ser humano precisa de música, afinal
    não importa o seu sabor, é sempre bom!

    Caso eu queira apenas coletar o texto dentro da frase abaixo, daria pra fazer usando grep e sed ?
    Acho que todo ser humano precisa de música afinal é sempre bom.

    To precisando coletar informações especificas de um log.

    • eitchugo disse:

      Se o texto estiver na mesma linha basta usar a opção "-o" do grep, assim:

      echo "Isto é uma frase completa em uma linha, e vou ter que extrair só uma parte dela" | grep -o "completa em uma linha"

      Saída vai ser apenas:

      completa em uma linha

      • Narviksw disse:

        Muito obrigado, mas o que eu realmente preciso é pegar este log :

        Mar 24 08:52:00 blabla postfix/smtpd[2114]: NOQUEUE: reject: RCPT from blu0-omc4-s5.blu0.hotmail.com[65.55.111.144]: 554 5.7.1 Service unavailable; Client host [65.55.111.144] blocked using cbl.anti-spam.org.cn; Mail from 65.55.111.144 refused, see http://www.anti-spam.org.cn/rbl_search.action?ip=… from=<[email protected]> to=<[email protected]> proto=ESMTP helo=<blu0-omc4-s5.blu0.hotmail.com>

        E deixar assim:

        Mar 24 08:52:00 reject: Client host [65.55.111.144] blocked using cbl.anti-spam.org.cn; from=<[email protected]> to=<[email protected]>

        Usei os comandos cat /home/socrates/teste2.txt | grep -i blocked | awk '{print $1,$2,$3,$21$22}'
        Só que pega apenas algumas informações.

        Pode me auxiliar , por gentielza ?

        Grato.

        • eitchugo disse:

          Tente quebrar por partes, exemplo:

          #!/bin/bash
          STRING='Mar 24 08:52:00 blabla postfix/smtpd[2114]: NOQUEUE: reject: RCPT from blu0-omc4-s5.blu0.hotmail.com[65.55.111.144]: 554 5.7.1 Service unavailable; Client host [65.55.111.144] blocked using cbl.anti-spam.org.cn; Mail from 65.55.111.144 refused, see http://www.anti-spam.org.cn/rbl_search.action?ip=…. from=<[email protected]> to=<[email protected]> proto=ESMTP helo=<blu0-omc4-s5.blu0.hotmail.com>'

          DATA=$(echo $STRING | awk '{print $1 " " $2 " " $3}')
          CLIENT=$(echo $STRING | sed -r "s/.* Client host \[([0-9\.]+)\] blocked.*/\1/")
          USING=$(echo $STRING | sed -r "s/.* blocked using ([[:graph:]]+); .*/\1/")
          FROM=$(echo $STRING | sed -r "s/.* from=<(.*)> to.*/\1/")
          TO=$(echo $STRING | sed -r "s/.* to=<(.*)> proto.*/\1/")

          echo $DATA
          echo $CLIENT
          echo $USING
          echo $FROM
          echo $TO

  14. Narviksw disse:

    Boa tarde,

    Preciso pesquisar numeros de telefones dentro de uma pasta com varios subdiretorios por data.
    Ex : na pasta Gravacoes do ano 2014 e mes de março 03
    #gravacoes/2014/03
    Dentro dela tenho subpastas do dia 01 ao dia 31 ( cada dia é uma pasta )
    Preciso pesquisar o numero 1133550967 apenas nas pastas de 10 a 30 deste diretorio.

    Da pra fazer isso com o grep ?
    Como posso resolver ?

    Grato pela ajuda.

    • eitchugo disse:

      Isso tem mais haver com shell-script do que o grep em si. por exemplo:

      cd gravacoes/2014/03
      for DIA in $(seq -w 10 30); do
      grep 1133550967 $DIA/*
      done

      (Faz uma iteração de 10 a 30, rodando um grep em todos os arquivos de cada um desses diretorios).

      Este é só um exemplo, pode-se usar outras lógicas com shell-script.

  15. Paul disse:

    Text format example :

    AA
    CC
    BB
    AA
    CC
    CC
    AA
    BB
    CC
    AA

    I need to get only this sequence of lines:

    AA
    BB
    CC

    Any suggestion for use grep, awk or sed in this case?

    • eitchugo disse:

      [eitch@raiden ~]$ grep -Pzo “(?s)^AA..BB..CC” input
      AA
      BB
      CC

      Fonte: http://stackoverflow.com/questions/3717772/regex-

      • Paul disse:

        Thanks eitchugo, but did not work for me.
        This is part of my text

        OXI -1.91299999 -2.67600012 4.00299978 -0.833999991 8536
        H1 -1.60599995 -2.15700006 3.23799992 0.416999996 8536
        H2 -1.20700002 -2.46700001 4.66200018 0.416999996 8536
        OXI 3.93600011 -5.17999983 5.67500019 -0.833999991 8556
        H1 4.61499977 -4.49599981 5.82700014 0.416999996 8556
        H2 3.72300005 -5.42700005 6.58300018 0.416999996 8556
        OXI -6.19999981 3.69099998 9.39400005 -0.833999991 8822
        H2 -6.58199978 3.88499999 8.51099968 0.416999996 8822
        OXI -9.61499977 5.48400021 -0.384999990 -0.833999991 8852
        H1 -9.66399956 4.82399988 0.337000012 0.416999996 8852
        H2 -9.17099953 4.96299982 -1.07299995 0.416999996 8852
        OXI -7.59399986 -2.11299992 4.37099981 -0.833999991 8887

        and I need to get only this sequence of lines :

        OXI ……….
        H1 ……….
        H2 ……..

        I try $ grep -Pzo "(?s)^OXI..H1..H2" file.txt but not work!
        Any other suggestion?

        PS. Sorry, Iam a new linux-user, thank you for your attention.

        • eitchugo disse:

          In this example, ".." (two dots) means a newline (for further explanation see the stackoverflow source link)

          Since you have content after the three letters, you must also include them on your regular expression, like this:

          grep -Pzo "(?s)^OXI\\N+..H1\\N+..H2\\N+" input

          The \N+ after OXI/H1/H2 means any character that isn't a new line. So the regex says: "Find three consecutive lines beginning with OXI, H1 and H2."

          You'll also want to convert the txt file to unix format for proper handling newlines with this regex:

          dos2unix input

  16. sutaina disse:

    Olá! Quero saber se é possível que a string a ser substituída seja definida por um arquivo de texto. Por exemplo, se ao invés de "música", no seu exemplo, eu tivesse um arquivo.txt com as strings a serem substituídas, e no lugar de "Linux" eu tivesse um outro .txt com as strings novas.

    • eitchugo disse:

      Se eu entendi, pode ser que sim… Supondo que o arquivo que tenha as strings a se substiyuir seja um de/para no formato:

      string1:substituto1
      string2:substituto2
      string3:substituto3

      (Importante que seja um caracter como dois pontos, e sem espaços, senao tem que tratar melhor)

      Pode-se ler cada linha, separar os campos por dois pontos e ir fazendo o sed no outro.txt:

      for STRINGS in $(cat arquivo.txt); do
      PATTERN=$(echo "$STRINGS" | cut -d ":" -f1)
      REPLACE=$(echo "$STRINGS" | cut -d ":" -f2)
      sed -i -r "s/$PATTERN/$REPLACE/g" outro.txt
      done

  17. sutaina disse:

    Outra dúvida, caso a dúvida acima não possua resposta. É possível especificar apenas parte da palavra a ser substituída? Por exemplo, todas as linhas iniciadas com "mus" seriam substituídas por "Linux"… algo do tipo sed -i 's/mus*/Linux/g temp. E aí o texto

    "Musica é demais!
    Adoro música"

    se tornaria

    "Linux
    Adoro música"

    Obrigada

    • eitchugo disse:

      Sim, você pode usar a expressão regular no sed para achar um padrão e remover todo o resto. Como o sed verifica linha por linha, no exemplo ficaria:

      sed -i "s/.*(Musica).*/\1/" arquivo

      O que singifica: Se a linha tiver a palavra Musica no meio, substituir deixando apenas a palavra Musica. O "\1" corresponde ao grupo que foi encontrado entre parenteses na busca, que no caso é a palavra Musica. Os ".*" antes e depois da palavra significam qualquer caracter quantas vezes for, o que significa todo o resto da linha.

      • sutaina disse:

        Obrigada eitchugo!

        Era exatamente o que eu precisava. Infelizmente, para o meu caso, está dando um probleminha. No caso o termo a ser localizado é um double (7.300000e+2), e não a palavra Musica, mas por alguma razão, o sed não entende a sintaxe (7.30000e+2).* . Ele até substitui o termo sozinho (7.30000e+2) por outro termo qualquer, mas com o asterisco ele não funciona. O curioso é que com palavras, ou números sem pontos, ele entende bem a função do asterisco. Sabe me dizer se há alguma opção (tentei -r -s –prefix) que entenda (7.30000e+2) como uma string?

        Obrigada!

  18. Lucas correia disse:

    Preciso extrair sequências de arquivos fasta de acordo com a ID. Por exemplo:

    O meu arquivo .fasta contem as sequências abaixo:

    >g1
    AAAAATTT

    >g2
    TTTAACG

    >g3
    TACG

    >g4
    TTAG

    Digamos que eu precise extrair apenas as ID's >g4 e >g1 juntamente as suas sequências de letras correspondentes que estão na linha logo abaixo, é possível fazer isso pelo grep ??? Se puderes me ajudar agradeço desde já!!!

    • eitchugo disse:

      Não sei exatamente o output que você quer, mas o -A1 do grep mostra uma linha posterior a que voce achou, então no seu exemplo eu procuro por uma expressao regular e ele retorna tambem a linha abaixo:

      $ grep -A1 -E "^>g(1|4)" input
      >g1
      AAAAATTT

      >g4
      TTAG

      • Lucas correia disse:

        Muito obrigado hugo!

        eu quero que na saida venha um arquivo com as sequências as quais desejo, no caso de as sequências terem números de linhas diferentes teria como usar tipo algum delineamento definisse isso pra mim ?

        Ex:

        >g1
        ATGCATTT
        TTGGCATC
        ATGCAATT

        >g2
        AAATCGGC
        CCKAJAOAO

        Teria como extrair as mesmas do começo ao fim ?

  19. Bill2602 disse:

    boa tarde, muito legal sua postagem…..
    Estou com uma dúvida:

    se eu salvar o nome de um arquivo em uma variável e quiser separar apenas a extensão como eu faço?
    Eu usei o comando : ext=`ls | grep -e $name | cut -d "." -f2`, porém ele mostra arquivos que nao tem extensão…

    Gostaria que quando existisse a extensão ele salvaria em ext, quando não, ficasse em branco.

    obrigado

  20. Antonio Cesario disse:

    muito legal. Aproveitando a oportunidade tenho um problema. Gostaria de contar uma palavra dentro de um arquivo texto, mas essa contagem deve começar após uma data que esta em formato computertime que também esta dentro desse arquivo de texto é possível fazer isso ?. Obrigado Cesario

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *