Vejo muitos exemplos e páginas de manual sobre como fazer coisas como pesquisar e substituir usando sed, awk ou gawk.
Mas, no meu caso, tenho uma expressão regular que desejo executar em um arquivo de texto para extrair um valor específico. Não quero pesquisar e substituir. Isso está sendo chamado de bash. Vamos usar um exemplo:
Expressão regular de exemplo:
.*abc([0-9]+)xyz.*
Arquivo de entrada de exemplo:
a
b
c
abc12345xyz
a
b
c
Por mais simples que pareça, não consigo descobrir como chamar o sed / awk / gawk corretamente. O que eu esperava fazer é de dentro do meu script bash:
myvalue=$( sed <...something...> input.txt )
As coisas que experimentei incluem:
sed -e 's/.*([0-9]).*/\\1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/\\1/g' example.txt # extracts nothing
Respostas:
Meu
sed
(Mac OS X) não funcionou com+
. Em*
vez disso, tentei e adicioneip
tag para correspondência de impressão:Para combinar pelo menos um caractere numérico sem
+
, eu usaria:fonte
+
e então funcionou para mim:sed -n 's/^.*abc\([0-9]\+\)xyz.*$/\1/p'
Você pode usar o sed para fazer isso
-n
não imprima a linha resultante-r
isso faz com que você não tenha como escapar dos parênteses do grupo de captura()
.\1
a partida do grupo de captura/g
jogo global/p
imprima o resultadoEu escrevi uma ferramenta para mim que torna isso mais fácil
fonte
Eu uso
perl
para tornar isso mais fácil para mim. por exemploIsso executa o Perl, a
-n
opção instrui o Perl a ler uma linha de cada vez de STDIN e executar o código. A-e
opção especifica a instrução a ser executada.A instrução executa um regexp na linha lida e, se corresponder, imprime o conteúdo do primeiro conjunto de bracks (
$1
).Você pode fazer isso com vários nomes de arquivo no final também. por exemplo
perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt
fonte
Se a sua versão do
grep
suportar, você pode usar a-o
opção de imprimir apenas a parte de qualquer linha que corresponda ao seu regexp.Se não, aqui está o melhor que
sed
eu poderia fazer:... que exclui / pula sem dígitos e, para as linhas restantes, remove todos os caracteres não-dígitos iniciais e finais. (Estou apenas supondo que sua intenção é extrair o número de cada linha que contém um).
O problema com algo como:
.... ou
... é que
sed
suporta apenas correspondência "gananciosa" ... então o primeiro. * corresponderá ao resto da linha. A menos que possamos usar uma classe de caractere negada para obter uma correspondência não gananciosa ... ou uma versãosed
com compatível com Perl ou outras extensões para seus regexes, não podemos extrair uma correspondência de padrão precisa com o espaço de padrão (uma linha )fonte
sed
comandos desta forma:sed -n 's/[^0-9]*\([0-9]\+\).*/\1/p'
grep -o
! Eu estava tentando fazer issosed
e lutava com minha necessidade de encontrar várias correspondências em algumas linhas. Minha solução é stackoverflow.com/a/58308239/117471Você pode usar
awk
commatch()
para acessar o grupo capturado:Isso tenta corresponder ao padrão
abc[0-9]+xyz
. Se fizer isso, ele armazena suas fatias no arraymatches
, cujo primeiro item é o bloco[0-9]+
. Comomatch()
retorna a posição do caractere, ou índice, de onde essa substring começa (1, se começar no início da string) , ele aciona aprint
ação.Com
grep
você pode usar um olhar para trás e para o futuro:Isso verifica o padrão
[0-9]+
quando ocorre dentro deabc
exyz
e apenas imprime os dígitos.fonte
perl é a sintaxe mais limpa, mas se você não tiver perl (nem sempre lá, eu entendo), então a única maneira de usar gawk e componentes de um regex é usar o recurso gensub.
a saída do arquivo de entrada de amostra será
Nota: gensub substitui todo o regex (entre //), então você precisa colocar o. * Antes e depois do ([0-9] +) para se livrar do texto antes e depois do número na substituição.
fonte
match()
para acessar os grupos capturados. Veja minha resposta para isso.Se você deseja selecionar linhas, retire os bits que você não deseja:
Basicamente, ele seleciona as linhas que você deseja
egrep
e usased
para remover os bits antes e depois do número.Você pode ver isso em ação aqui:
Atualização: obviamente, se sua situação real for mais complexa, os REs precisarão ser modificados. Por exemplo, se você sempre teve um único número dentro de zero ou mais números não numéricos no início e no final:
fonte
O caso do OP não especifica que pode haver várias correspondências em uma única linha, mas para o tráfego do Google, adicionarei um exemplo para isso também.
Como a necessidade do OP é extrair um grupo de um padrão, o uso
grep -o
exigirá 2 passagens. Mas, ainda acho esta a maneira mais intuitiva de fazer o trabalho.Como o tempo do processador é basicamente gratuito, mas a legibilidade humana não tem preço, tendo a refatorar meu código com base na pergunta: "daqui a um ano, o que vou pensar que isso faz?" Na verdade, para código que pretendo compartilhar publicamente ou com minha equipe, vou até abrir
man grep
para descobrir quais são as opções longas e substituí-las. Igual a:grep --only-matching --extended-regexp
fonte
você pode fazer isso com a concha
fonte
Por awk. Eu usaria o seguinte script:
fonte
([0-9+])
, mas sim a linha inteira.fonte