Como alterar um valor numérico desconhecido com o awk

0

Eu sou novo em aprender awk .
Eu tenho um arquivo que contém a seguinte linha, junto com outras linhas:

TIMEOUT=200

Eu preciso alterar o valor numérico.
Este comando só pode alterar o valor se eu souber o valor de antemão:

awk '$0 == "TIMEOUT=200" { sub ("200","5") } { print }' file

Qual comando devo usar se não souber o valor?
Algo parecido com isto:

awk '$0 == "TIMEOUT=[0-9]" { sub ("[0-9]","5") } { print }' file

Mas eu tentei esse comando e isso não muda nada.

    
por Rifatt 06.01.2017 / 03:12

1 resposta

1

  • Sua tentativa não funciona porque == testa apenas a igualdade exata. Se o seu arquivo continha uma linha que dizia exatamente e literalmente TIMEOUT=[0-9] , seu código reconheceria (e mude para TIMEOUT=[5-9] ). Mas, como você viu, não corresponde a strings como TIMEOUT=42 . Você, claro, quer selecionar linhas que correspondem ao padrão TIMEOUT=number . Uma maneira de fazer isso é usar o operador ~ em vez de == :
    awk '$0 ~ "TIMEOUT=[0-9]" { action statement(s) }'
  • É bom entender como usar o operador ~ e saber que você pode fazer testes em campos individuais. Contudo, Há uma notação abreviada para corresponder a linha inteira a um padrão:
    awk '/TIMEOUT=[0-9]/      { action statement(s) }'
    e você pode querer usar isso quando puder.
  • Então, agora, se fizermos
    awk '/TIMEOUT=[0-9]/ { sub ("[0-9]","5") } { print }'
    corresponderá à linha TIMEOUT=200 - e altere para TIMEOUT=500 , porque [0-9] corresponde apenas a um único dígito (numeral) e não um número de vários dígitos. Para encontrar (e substituir) um número com vários dígitos (uma sequência de um ou mais numerais consecutivos), use o caractere + (operador), que significa “uma ou mais ocorrências do padrão precedente”, como em sub ("[0-9]+","5") .
  • Mas eu encarei um problema anteriormente nesta lista. Embora == teste a igualdade exata da sequência completa , ~ "pattern" e %código% teste para uma string contendo uma substring que corresponda ao padrão. Então, por exemplo, /pattern/ irá coincidir com uma linha que se parece
    In American football, a TIMEOUT=30seconds
    Se estiver tudo bem com você, tudo bem. Eu imagino que você queira combinar apenas uma linha completa, então você vai querer "ancorar" o padrão para que /TIMEOUT=[0-9]/ esteja no começo da linha, e o número deve estar no final. Você faz isso com os caracteres TIMEOUT e ^ , como em $ .
    Exceto…
  • … conforme mencionado anteriormente, /^TIMEOUT=[0-9]$/ corresponde apenas a um único dígito, então, o que está acima corresponderá a [0-9] , mas não a TIMEOUT=7 . Você precisa de TIMEOUT=11 .

TL; DR

Você precisa fazer

awk '$0 ~ "^TIMEOUT=[0-9]+$" { sub ("[0-9]+","5") } { print }'  file
ou

awk '/^TIMEOUT=[0-9]+$/      { sub ("[0-9]+","5") } { print }'  file

Incentivo você a aprender /^TIMEOUT=[0-9]+$/ , pois pode ser muito útil e muito poderoso. No entanto, para uma tarefa simples como essa, você pode obter uma ferramenta mais simples: awk .

Infelizmente, sed normalmente não suporta o operador sed (um ou mais). No GNU + (a versão que vem com o Cygwin e a maioria (se não todas) distribuições Linux), você pode especificar a opção sed para dizer para reconhecer "expressões regulares estendidas". (Padrões como -r são chamados de "expressões regulares".) Então você poderia fazer

sed -r '/^TIMEOUT=[0-9]+$/s/[0-9]+/5/'

Mas algumas versões (mais antigas) de [0-9]+ não honram a opção sed e não suportam expressões regulares estendidas. Felizmente, você pode contornar isso: há outro caractere especial (operador), -r , que significa “ zero ou mais ocorrências do padrão anterior”. "Um ou mais dígitos" é equivalente a "Um dígito, seguido por zero ou mais dígitos adicionais" então podemos traduzir * para [0-9]+ e fazer o comando como

sed '/^TIMEOUT=[0-9][0-9]*$/s/[0-9][0-9]*/5/'

Em vez de [0-9][0-9]* , você também pode fazer [0-9][0-9]* (um dígito, precedido por zero ou mais dígitos adicionais). Eu prefiro a segunda forma, porque eu acho que parece mais equilibrado, mas não é muito popular.

    
por 10.01.2017 / 20:56