Aplicando um regex para stdin

4

Na programação, muitas vezes vemos o uso de Expressões regulares .

Uma das formas mais comuns é:

newText = text.replace( /regex/, 'replacementString' )

Se stdin for text e stdout for newText , qual seria o equivalente da bash ao código acima?

    
por Stefan 29.10.2010 / 09:47

4 respostas

6

Para usos simples, você pode fazer assim:

newText=${text/SEARCH/replacement}

como é descrito aqui , mas para expressões mais complexas sed é o caminho a percorrer como alex descrito anteriormente.

    
por 29.10.2010 / 10:13
4
  • man sed
  • sed s/regex/replacementString/g
por 29.10.2010 / 10:05
4

A resposta mais direta é o comando sed s . Você precisa converter a sintaxe regexp em Expressões regulares básicas , e a substituição será aplicada sucessivamente em cada linha. Você pode usar a para se referir a grupos entre parênteses na string original. Adicione o modificador g para substituir todas as ocorrências; caso contrário, apenas a primeira ocorrência será substituída.

sed -e 's/basic regexp/replacement string/g'

Um utilitário mais flexível é awk . Ele também processa sua entrada linha por linha por padrão, mas você pode alterar o separador de registro com -vRS=… (padrão awk quer um único caractere ou um valor vazio para significar duas ou mais novas linhas; Gawk (a versão GNU) aceita um regular expressão). A função sub executa uma única substituição e gsub substitui todas as ocorrências. A string de substituição é interpretada literalmente, exceto por \ e & ; Se você quiser se referir a grupos entre parênteses, poderá usar as funções match e subtring .

awk '{gsub(/regexp/, "replacement string")}'

O Bash tem suporte interno para correspondência de expressões regulares: [[ text =~ regexp ]] . Você pode construir um texto de substituição usando substrings correspondidas armazenadas na matriz BASH_REMATCH . Use read ou cat para obter a entrada e printf para emitir a saída. O pseudocódigo a seguir executa várias substituições (aviso, não testado; o código deve executar várias substituições da esquerda para a direita, como é normal, espero ter acertado).

# The end marker must not have a prefix that is a suffix of a match of the regexp,
# and must not start or end with a newline
end_marker='EOF'
text=$(cat; echo "$end_marker")
while [[ $text =~ regexp(.*)$ ]]; then
    printf %s%s "${text%"$BASH_REMATCH[0]"}" "replacement string"
    text=$BASH_REMATCH[$#BASH_REMATCH]
  fi
done
printf %s "${text%"$end_marker"}"

(Algumas palavras de explicação: o marcador final é para evitar que novas linhas sejam removidas pela substituição do comando. ${text%"$BASH_REMATCH[0]"} extrai a parte do texto que veio antes da correspondência. Observe que não podemos usar ^(.*) no início do regexp ou teríamos o último jogo em vez do primeiro. Após a partida, nós iteramos sobre o sufixo. Finalmente, imprimimos a sobra inigualável, menos o marcador final.)

Se você estiver satisfeito com as habilidades de correspondência de caracteres curinga e de texto de substituição limitada, o bash também terá ${variable/pattern/replacement} . Duplique a primeira barra para substituir todas as ocorrências. Os padrões têm o poder das expressões regulares (mas com uma sintaxe incomum) se a opção extglob estiver definida.

    
por 29.10.2010 / 23:03
-1

você pode usar ferramentas como sed e awk , mas na minha opinião elas são muito antiquadas e úteis apenas para tarefas definidas de forma restrita.

uma aposta melhor é redirecionar STDIN para um perl one-liner ou script. O suporte a regex do perl é tão bom que a maioria das outras linguagens agora suporta alguma compatibilidade com elas. Existem até a2p e s2p ferramentas para transformar sed e awk diretamente em perl. O uso do perl permite que você use a totalidade do CPAN para ajudá-lo a resolver seus problemas.

e se você não gosta de perl, você pode usar python em uma capacidade similar.

    
por 30.10.2010 / 06:30