Como você salva um regex complexo para a reutilização múltipla no sed?


12

Ao usar sed, geralmente crio regexes bastante complicadas e intricadas que precisam ser correspondidas duas vezes em um arquivo. Existe uma maneira de eu salvar esse regex e apenas referenciá-lo duas vezes?

Talvez algo parecido com isso?

sed ' complicated_regex=/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+$/
s/complicated_regex:complicated_regex/simple-output/
' my_file

Atualização: Uma resposta apresentou a solução do uso de uma variável bash. Isso não funciona. Dado a test.txt.

#test.txt
foo bar
bar foo

E o roteiro

#!/bin/bash

VALUE='foo \([a-z]\+\)'

sed 's/"${VALUE}"/foo happy \1/' test.txt

Isso deve produzir a saída

foo happy bar
bar foo

Mas, em vez disso, recebo o erro

sed: -e expression #1, char 24: invalid reference \1 on `s' command's RHS

Se você usa Perl, pode fazer referência a partes anteriores da expressão dentro da expressão:perl -pe 's/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+:\1$/simple_output/' my_file
glenn jackman

1
Quando você encontrar algo muito complicado para o sed, não hesite em procurar awk ou perl.
Gilles 'SO- stop be evil'

2
@Cory: Seu exemplo funciona bem, se você obtiver a sintaxe correta. Você tem a "variável $" ainda fechado em 'aspas simples', que esconde de expansão shell você espera ... deve sersed 's/'"${VALUE}"'/foo happy \1/' test.txt
Peter.O

Respostas:


7

Você pode usar variáveis ​​de shell:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+'
sed s/^"$complicated_regex":"$complicated_regex"\$/'simple-output'/ my_file

Não sei ao certo o que você quis dizer com isso $i, mas pode ser necessário colocá-lo fora de aspas simples:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{'"$i"'}})?)+'

Obviamente, isso funciona apenas se o sedcomando for chamado do shell, mas há uma solução semelhante com quase todas as linguagens de programação. (E eu não acho que é possível usar variáveis dentro sed.)
Stéphane Gimenez

Hrm. Tentando isso, as referências anteriores parecem estar quebradas. s/$complicated_regex/\1/dá um erro dizendo que é uma referência inválida.
Cory Klein

Ah, talvez seja minha culpa, estou acostumado a substituições de variáveis ​​do zsh. Veja a resposta atualizada.
Stéphane Gimenez

Você terá que remover as âncoras da variável e colocá-las no script sed:sed "s/^${complicated_regex}:${complicated_regex}\$/simple-output/" my_file
glenn jackman

Duh! Sim, eu esqueci de verificar que foi prestada uma concatenação regex válida :-)
Stéphane Gimenez

0

A maneira mais fácil de inserir um valor de variável do shell sede não se preocupar com a forma como o escape de barra invertida precisará mudar para o restante do seu sedscript, é colocar tudo entre aspas simples, exceto a variável, e colocar entre aspas duplas.

Todos os seguintes exemplos de código assumem: VALUE='foo \([a-z]\+\)'

O código quebrado a seguir falha porque a variável VALUEnão é expandida:

sed 's/"${VALUE}"/foo happy \1/' test.txt

O código quebrado a seguir falha porque a barra invertida \1é consumida pelo shell (porque está entre aspas duplas e não entre aspas simples) antes sedmesmo de ser vista:

sed "s/${VALUE}/foo happy \1/" test.txt

O código a seguir funciona conforme o esperado:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt

O código a seguir também funciona:

sed "s/${VALUE}/foo happy \\1/" test.txt

O mesmo acontece com o seguinte:

sed s/"${VALUE}"/foo\ happy\ \\1/ test.txt

Mas por que ficar complicado? As aspas simples ao redor de um sedscript tornam tudo muito mais claro, especialmente para os gurus que não são de shell que lêem seu código. Minha maneira preferida é, novamente, deixar de aspas simples para aspas duplas apenas para a expansão da variável e voltar direto para aspas simples:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.