Referenciando com &
Sempre que o sed casa algo, ele armazena esse algo em " & ".
Por exemplo: s/javali/porco/
Nesse caso: &=javali
Vamos usar o & para repetir cada número do "teste.txt":
cat teste.txt | sed 's/./&&/g'
" . " (ponto)-> Representa um único caractere. Como, no "teste.txt", cada linha possui somente um caractere, que é um número, o & armazenará o valor deste número, em cada linha.
Estamos substituindo um número (.), por ele duas vezes(&&).
Vamos para um exemplo prático. Vamos supor que você tem um site que pede o telefone do cliente, com DDD+número, sem parênteses ou hífens.
Crie: tels.txt
2134567890
8588887766
8599001122
Porém, exibir um número assim é confuso. Pra armazenar no seu banco de dados, OK. Mas para exibir isso pro cliente, não é interessante.
Então, vamos fazer um script em sed que pegue um ".txt" contendo telefones e transforme no padrão: (DDD)NUMEROS-NUMEROS
1. Vamos pegar os dois primeiros números e transformar neles envoltos de parênteses.
Para pegar os 2 primeiros números do início de cada linha:
's/^[[:digit:]][[:digit:]]/(&)/g'
Ou seja, o que vai casar, dois dígitos seguidos, fica armazenado na & e vamos colocar, no lugar desses dois números, isso (&). Mas é muito chato escrever [[:digit:]] duas vezes, pois, e se fossem 10 números e não só 2?
Para repetição, usamos o número de vezes que queremos repetir entre colchetes: {n}. No nosso caso, seria:
[[:digit:]]{2}
Vamos colocar isso no script, lembrando que temos que 'escapar' '{' e '}':
's/^[[:digit:]]\{2\}/(&)/g'
2. Depois de colocar os parênteses, devemos colocar um hífen após 4 dígitos.Como dizer isso pro sed? Simples.
Seja 'abcd' os números, queremos substituir isso por 'abcd-'. Mas não pode ser quatro números quaisquer, tem que ser os 4 dígitos após o parêntese " ) ".
Então, fica:
s/)[[:digit:]]\{4\}/&-/g
3. Lembrando que, o comando 2. só funciona se a substituição referente ao item 1, já tiver ocorrido. Ou seja, vamos colocar os comandos em sequência, e usaremos a flag '-e' para edições múltiplas.
O resultado é:
cat tels.txt | sed -e 's/^[[:digit:]]\{2\}/(&)/' -e 's/)[[:digit:]]\{4\}/&-/' > tels2.txt
E obtemos na "tels2.txt":
(21)3456-7890
(85)8888-7766
(85)9900-1122
Back reference
'&' só não é mais útil porque é só um.
No exemplo anterior, fizemos duas alterações no número. Imagine porém, se ao invés de duas, tivéssemos que fazer várias edições numa linha.
Faríamos " -e 's///' " várias vezes? Não, daria muito trabalho. Vamos usar
back reference!
Coloque cada coisa que você quer casar entre parênteses. Ou seja, faça sua regex normalmente, mas ponha trechos dela entre parênteses. A cada trecho entre parênteses, o sed guarda o que foi casado em '\1', '\2', ..., em quantos trechos você tenha criado, para que você possa trabalhar com várias coisas que casaram, no mesmo comando.
Lembrando que para usar parênteses no sed, você tem que escapá-lo : \(\)
Vamos pegar o arquivo gerado no exemplo passado, o "tels2.txt", e explicitar mais cada trecho do telefone.
1. Código de área
O código de área é tudo que está do início até ')'. Como o analisador de linha do sed inicia no começo da linha, não é necessário explicitar isso, o ^ .
Veja: .*)
Colocando esse trecho entre parênteses(escapados) para depois referenciá-lo: \(.*)\)
Pronto. Se o sed achar um trecho do tipo: (nn), ele armazenará o que achar em '\1', onde 'n' é um caractere qualquer.
2. Primeira parte do número
São os quatro primeiros números do telefone, antes do hífen e depois dos parênteses.
Eles podem ser achados entre ')' e '-' . Porém, aqui tem um detalhe. Como anteriormente já casamos o trecho inicial (nn), a análise de linha do sed está localizada após o ')', pois vamos colocar tudo num comando só, como você verá mais à frente.
Portanto, não escrevemos: ).*-
E sim: .*-
Ou seja, catamos tudo, desde o ')', até o hífen.
Colocando entre parênteses, escapando: \(.*\)
Agora, os 4 primeiros números, fora o DDD, está em '\2'.
3. Agora, o analisador de linha do sed está localizado após o hífen e queremos pegar tudo do hífen até o final: .*$
Colocando entre parênteses e escapando: \(.*$\)
Esse trecho ficará em '\3'.
4. Agora vamos formatar a saída de modo a exibir uma mensagem bem mais detalhada sobre o telefone. Pra isso, colocamos tudo isso junto num 's///':
cat tels2.txt | sed 's/\(.*)\)\(.*-\)\(.*$\)/DDD: \1 Primeira parte: \2 Segunda parte: \3/g'
Note que pegamos tudo em sequência, de uma vez: primeiro o DDD, depois os 4 seguintes números e depois os 4 finais.
É como se nós tivéssemos usado o sed para dizer como é o formato do telefone: (nn)NUMERO-NUMERO
Como todos são neste formato, foi possível dividir em trechos: \1, \2 e \3
Isso só aconteceu graças à padronização dos dados.
E o resultado é:
DDD: (21) Primeira parte: 3456- Segunda parte: 7890
DDD: (85) Primeira parte: 8888- Segunda parte: 7766
DDD: (85) Primeira parte: 9900- Segunda parte: 1122