Unix / Linux - Expressões regulares com SED
Neste capítulo, discutiremos em detalhes sobre as expressões regulares com SED no Unix.
Uma expressão regular é uma string que pode ser usada para descrever várias sequências de caracteres. Expressões regulares são usadas por vários comandos Unix diferentes, incluindoed, sed, awk, grep, e em uma extensão mais limitada, vi.
Aqui SED apoia samarração editor. Este editor orientado a stream foi criado exclusivamente para a execução de scripts. Portanto, toda a entrada que você alimenta nele passa e vai para STDOUT e não altera o arquivo de entrada.
Invocando sed
Antes de começarmos, vamos garantir que temos uma cópia local do /etc/passwd arquivo de texto para trabalhar sed.
Conforme mencionado anteriormente, o sed pode ser invocado enviando dados por meio de um pipe para ele da seguinte maneira -
$ cat /etc/passwd | sed
Usage: sed [OPTION]... {script-other-script} [input-file]...
-n, --quiet, --silent
suppress automatic printing of pattern space
-e script, --expression = script
...............................
o cat comando despeja o conteúdo de /etc/passwd para sedatravés do tubo no espaço padrão do sed. O espaço padrão é o buffer de trabalho interno que o sed usa para suas operações.
Sintaxe geral do sed
A seguir está a sintaxe geral para sed -
/pattern/action
Aqui, pattern é uma expressão regular, e actioné um dos comandos fornecidos na tabela a seguir. E sepattern é omitido, action é executado para cada linha como vimos acima.
O caractere de barra (/) que circunda o padrão é obrigatório porque é usado como delimitador.
Sr. Não. | Alcance e descrição |
---|---|
1 | p Imprime a linha |
2 | d Exclui a linha |
3 | s/pattern1/pattern2/ Substitui a primeira ocorrência de pattern1 por pattern2 |
Excluindo todas as linhas com sed
Agora vamos entender como deletar todas as linhas com sed. Invoque sed novamente; mas o sed agora deve usar oediting command delete line, denotado por uma única letra d -
$ cat /etc/passwd | sed 'd'
$
Em vez de invocar o sed enviando um arquivo para ele por meio de um pipe, o sed pode ser instruído a ler os dados de um arquivo, como no exemplo a seguir.
O comando a seguir faz exatamente o mesmo que no exemplo anterior, sem o comando cat -
$ sed -e 'd' /etc/passwd
$
Os endereços sed
O sed também suporta endereços. Os endereços são locais específicos em um arquivo ou um intervalo onde um determinado comando de edição deve ser aplicado. Quando o sed não encontra endereços, ele executa suas operações em cada linha do arquivo.
O comando a seguir adiciona um endereço básico ao comando sed que você está usando -
$ cat /etc/passwd | sed '1d' |more
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
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
$
Observe que o número 1 é adicionado antes do delete editcomando. Isso instrui o sed a executar o comando de edição na primeira linha do arquivo. Neste exemplo, o sed excluirá a primeira linha de/etc/password e imprima o resto do arquivo.
Os intervalos de endereços sed
Agora vamos entender como trabalhar com the sed address ranges. E se você quiser remover mais de uma linha de um arquivo? Você pode especificar um intervalo de endereços com sed da seguinte forma -
$ cat /etc/passwd | sed '1, 5d' |more
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
$
O comando acima será aplicado em todas as linhas, começando de 1 a 5. Isso exclui as primeiras cinco linhas.
Experimente os seguintes intervalos de endereços -
Sr. Não. | Alcance e descrição |
---|---|
1 | '4,10d' As linhas que começam a partir da 4 th até a 10 th são eliminados |
2 | '10,4d' Apenas 10 ª linha é excluído, porque o sed não funciona no sentido inverso |
3 | '4,+5d' Isso corresponde à linha 4 do arquivo, exclui essa linha, continua a excluir as próximas cinco linhas e, em seguida, interrompe a exclusão e imprime o resto |
4 | '2,5!d' Isso exclui tudo, exceto a partir de 2 nd até 5 ª linha |
5 | '1~3d' Isso exclui a primeira linha, passa pelas próximas três linhas e, em seguida, exclui a quarta linha. O Sed continua a aplicar esse padrão até o final do arquivo. |
6 | '2~2d' Isso diz ao sed para deletar a segunda linha, passar pela próxima linha, deletar a próxima linha e repetir até o final do arquivo ser alcançado |
7 | '4,10p' As linhas que começam a partir de 4 th até 10 th são impressas |
8 | '4,d' Isso gera o erro de sintaxe |
9 | ',10d' Isso também geraria um erro de sintaxe |
Note - Ao usar o p ação, você deve usar o -nopção para evitar a repetição de impressão de linha. Verifique a diferença entre os dois comandos a seguir -
$ cat /etc/passwd | sed -n '1,3p'
Check the above command without -n as follows −
$ cat /etc/passwd | sed '1,3p'
O Comando de Substituição
O comando de substituição, denotado por s, substituirá qualquer string que você especificar por qualquer outra string que você especificar.
Para substituir uma string por outra, o sed precisa ter as informações sobre onde termina a primeira string e começa a string de substituição. Para isso, continuamos com a marcação das duas strings com a barra (/) personagem.
O seguinte comando substitui a primeira ocorrência em uma linha da string root com a corda amrood.
$ cat /etc/passwd | sed 's/root/amrood/'
amrood:x:0:0:root user:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
..........................
É muito importante observar que o sed substitui apenas a primeira ocorrência em uma linha. Se a raiz da string ocorrer mais de uma vez em uma linha, apenas a primeira correspondência será substituída.
Para o sed realizar uma substituição global, adicione a letra g ao final do comando da seguinte forma -
$ cat /etc/passwd | sed 's/root/amrood/g'
amrood:x:0:0:amrood user:/amrood:/bin/sh
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
...........................
Bandeiras de substituição
Existem vários outros sinalizadores úteis que podem ser passados além do g sinalizador e você pode especificar mais de um de cada vez.
Sr. Não. | Sinalizador e descrição |
---|---|
1 | g Substitui todas as correspondências, não apenas a primeira |
2 | NUMBER Substitui único número th jogo |
3 | p Se a substituição foi feita, então imprime o espaço do padrão |
4 | w FILENAME Se a substituição foi feita, então grava o resultado em FILENAME |
5 | I or i Corresponde sem fazer distinção entre maiúsculas e minúsculas |
6 | M or m Além do comportamento normal dos caracteres especiais da expressão regular ^ e $, este sinalizador faz com que ^ corresponda à string vazia após uma nova linha e $ corresponda à string vazia antes de uma nova linha |
Usando um Separador de String Alternativo
Suponha que você tenha que fazer uma substituição em uma string que inclui o caractere de barra. Neste caso, você pode especificar um separador diferente, fornecendo o caractere designado após os.
$ cat /etc/passwd | sed 's:/root:/amrood:g'
amrood:x:0:0:amrood user:/amrood:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
No exemplo acima, usamos : Enquanto o delimiter em vez de barra / porque estávamos tentando pesquisar /root em vez da raiz simples.
Substituindo com Espaço Vazio
Use uma string de substituição vazia para excluir a string raiz do /etc/passwd arquivo inteiramente -
$ cat /etc/passwd | sed 's/root//g'
:x:0:0::/:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
Substituição de Endereço
Se você quiser substituir a string sh com a corda quiet apenas na linha 10, você pode especificá-lo da seguinte maneira -
$ cat /etc/passwd | sed '10s/sh/quiet/g'
root:x:0:0:root user:/root:/bin/sh
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
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/quiet
Da mesma forma, para fazer uma substituição de intervalo de endereço, você poderia fazer algo como o seguinte -
$ cat /etc/passwd | sed '1,5s/sh/quiet/g'
root:x:0:0:root user:/root:/bin/quiet
daemon:x:1:1:daemon:/usr/sbin:/bin/quiet
bin:x:2:2:bin:/bin:/bin/quiet
sys:x:3:3:sys:/dev:/bin/quiet
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
Como você pode ver na saída, as primeiras cinco linhas tinham a string sh mudou para quiet, mas o resto das linhas não foram alteradas.
O Comando de Correspondência
Você usaria o p opção junto com o -n opção de imprimir todas as linhas correspondentes da seguinte forma -
$ cat testing | sed -n '/root/p'
root:x:0:0:root user:/root:/bin/sh
[root@ip-72-167-112-17 amrood]# vi testing
root:x:0:0:root user:/root:/bin/sh
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
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
Usando Expressão Regular
Ao combinar os padrões, você pode usar a expressão regular, que fornece mais flexibilidade.
Verifique o exemplo a seguir que corresponde a todas as linhas começando com daemon e depois as exclui -
$ cat testing | sed '/^daemon/d'
root:x:0:0:root user:/root:/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
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
A seguir está o exemplo que exclui todas as linhas que terminam com sh -
$ cat testing | sed '/sh$/d'
sync:x:4:65534:sync:/bin:/bin/sync
A tabela a seguir lista quatro caracteres especiais que são muito úteis em expressões regulares.
Sr. Não. | Descrição do personagem |
---|---|
1 | ^ Corresponde ao início das linhas |
2 | $ Corresponde ao final das linhas |
3 | . Corresponde a qualquer caractere único |
4 | * Corresponde a zero ou mais ocorrências do caractere anterior |
5 | [chars] Corresponde a qualquer um dos caracteres fornecidos em chars, onde chars é uma sequência de caracteres. Você pode usar o caractere - para indicar um intervalo de caracteres. |
Personagens Combinando
Veja mais algumas expressões para demonstrar o uso de metacharacters. Por exemplo, o seguinte padrão -
Sr. Não. | Expressão e Descrição |
---|---|
1 | /a.c/ Corresponde a linhas que contêm strings como a+c, a-c, abc, match, e a3c |
2 | /a*c/ Corresponde às mesmas strings com strings como ace, yacc, e arctic |
3 | /[tT]he/ Corresponde à string The e the |
4 | /^$/ Corresponde a linhas em branco |
5 | /^.*$/ Corresponde a uma linha inteira, seja ela qual for |
6 | / */ Corresponde a um ou mais espaços |
7 | /^$/ Partidas blank linhas |
A tabela a seguir mostra alguns conjuntos de caracteres usados com frequência -
Sr. Não. | Definir & Descrição |
---|---|
1 | [a-z] Corresponde a uma única letra minúscula |
2 | [A-Z] Corresponde a uma única letra maiúscula |
3 | [a-zA-Z] Corresponde a uma única letra |
4 | [0-9] Corresponde a um único número |
5 | [a-zA-Z0-9] Corresponde a uma única letra ou número |
Palavras-chave de classe de personagem
Algumas palavras-chave especiais estão comumente disponíveis para regexps, especialmente utilitários GNU que empregam regexps. Eles são muito úteis para expressões regulares sed, pois simplificam as coisas e aumentam a legibilidade.
Por exemplo, os personagens a through z e os personagens A through Z, constituem uma classe de caracteres que tem a palavra-chave [[:alpha:]]
Usando a palavra-chave da classe de caracteres do alfabeto, este comando imprime apenas as linhas no /etc/syslog.conf arquivo que começa com uma letra do alfabeto -
$ cat /etc/syslog.conf | sed -n '/^[[:alpha:]]/p'
authpriv.* /var/log/secure
mail.* -/var/log/maillog
cron.* /var/log/cron
uucp,news.crit /var/log/spooler
local7.* /var/log/boot.log
A tabela a seguir é uma lista completa das palavras-chave de classes de caracteres disponíveis no GNU sed.
Sr. Não. | Classe e descrição do personagem |
---|---|
1 | [[:alnum:]] Alfanumérico [az AZ 0-9] |
2 | [[:alpha:]] Alfabético [az AZ] |
3 | [[:blank:]] Caracteres em branco (espaços ou tabulações) |
4 | [[:cntrl:]] Personagens de controle |
5 | [[:digit:]] Números [0-9] |
6 | [[:graph:]] Quaisquer caracteres visíveis (exclui espaços em branco) |
7 | [[:lower:]] Letras minúsculas [az] |
8 | [[:print:]] Caracteres imprimíveis (caracteres sem controle) |
9 | [[:punct:]] Caracteres de pontuação |
10 | [[:space:]] Espaço em branco |
11 | [[:upper:]] Letras maiúsculas [AZ] |
12 | [[:xdigit:]] Dígitos hexadecimais [0-9 af AF] |
Aampersand Referencing
o sed metacharacter &representa o conteúdo do padrão que foi correspondido. Por exemplo, digamos que você tenha um arquivo chamadophone.txt cheio de números de telefone, como os seguintes -
5555551212
5555551213
5555551214
6665551215
6665551216
7775551217
Você quer fazer o area code(os três primeiros dígitos) entre parênteses para facilitar a leitura. Para fazer isso, você pode usar o caractere de e comercial de substituição -
$ sed -e 's/^[[:digit:]][[:digit:]][[:digit:]]/(&)/g' phone.txt
(555)5551212
(555)5551213
(555)5551214
(666)5551215
(666)5551216
(777)5551217
Aqui na parte do padrão, você está combinando os primeiros 3 dígitos e, em seguida, usando & você está substituindo esses 3 dígitos com os parentheses.
Usando vários comandos sed
Você pode usar vários comandos sed em um único comando sed da seguinte maneira -
$ sed -e 'command1' -e 'command2' ... -e 'commandN' files
Aqui command1 através commandNsão comandos sed do tipo discutido anteriormente. Esses comandos são aplicados a cada uma das linhas na lista de arquivos fornecida por arquivos.
Usando o mesmo mecanismo, podemos escrever o exemplo de número de telefone acima da seguinte forma -
$ sed -e 's/^[[:digit:]]\{3\}/(&)/g' \
-e 's/)[[:digit:]]\{3\}/&-/g' phone.txt
(555)555-1212
(555)555-1213
(555)555-1214
(666)555-1215
(666)555-1216
(777)555-1217
Note - No exemplo acima, em vez de repetir a palavra-chave da classe de caracteres [[:digit:]] três vezes, nós o substituímos por \{3\}, o que significa que a expressão regular anterior é correspondida três vezes. Nós também usamos\ para fornecer quebra de linha e isso deve ser removido antes de o comando ser executado.
Referências anteriores
o ampersand metacharacteré útil, mas ainda mais útil é a capacidade de definir regiões específicas em expressões regulares. Essas regiões especiais podem ser usadas como referência em suas strings de substituição. Ao definir partes específicas de uma expressão regular, você pode então se referir a essas partes com um caractere de referência especial.
Façam back references, você deve primeiro definir uma região e depois se referir a essa região. Para definir uma região, você inserebackslashed parenthesesem torno de cada região de interesse. A primeira região que você cerca com barras invertidas é então referenciada por\1, a segunda região por \2, e assim por diante.
Assumindo phone.txt tem o seguinte texto -
(555)555-1212
(555)555-1213
(555)555-1214
(666)555-1215
(666)555-1216
(777)555-1217
Tente o seguinte comando -
$ cat phone.txt | sed 's/\(.*)\)\(.*-\)\(.*$\)/Area \
code: \1 Second: \2 Third: \3/'
Area code: (555) Second: 555- Third: 1212
Area code: (555) Second: 555- Third: 1213
Area code: (555) Second: 555- Third: 1214
Area code: (666) Second: 555- Third: 1215
Area code: (666) Second: 555- Third: 1216
Area code: (777) Second: 555- Third: 1217
Note - No exemplo acima, cada expressão regular entre parênteses seria referenciada novamente por \1, \2e assim por diante. Nós usamos\para dar quebra de linha aqui. Isso deve ser removido antes de executar o comando.