Я новичок в изучении awk .
У меня есть файл, который содержит следующую строку, наряду с другими строками:

TIMEOUT=200

Мне нужно изменить числовое значение.
Эта команда может изменить значение, только если я знаю значение заранее:

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

Какую команду я должен использовать, если я не знаю значение?
Что-то вроде этого:

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

Но я попробовал эту команду, и она ничего не меняет.

1 ответ1

1
  • Ваша попытка не работает, потому что == проверяет только на точное равенство.  Если ваш файл содержит строку, в которой точно и буквально указано TIMEOUT=[0-9] , ваш код распознает его (и изменит его на TIMEOUT=[5-9]).  Но, как вы видели, он не совпадает со строками типа TIMEOUT=42 .  Вы, конечно, хотите выбрать линии, которые соответствуют шаблону TIMEOUT=number .  Один из способов сделать это - использовать оператор ~ вместо ==:
    awk '$ 0 ~ "TIMEOUT = [0-9]" { оператор (ы) действия }'
  • Хорошо понимать, как использовать оператор ~ , и знать, что вы можете выполнять тесты на отдельных полях.  Тем не менее, существует условное обозначение для сопоставления всей строки с шаблоном:
    awk '/TIMEOUT = [0-9]/ { оператор (ы) действия }'
    и вы можете использовать это, когда можете.
  • Так что теперь, если мы сделаем
    awk '/TIMEOUT = [0-9]/ {sub ("[0-9]", "5")} {print}'
    он будет соответствовать строке TIMEOUT=200 - и изменится на TIMEOUT=500 , потому что [0-9] соответствует только одной цифре (цифре), а не многозначной цифре.  Чтобы найти (и заменить) многозначное число (строку из одной или нескольких последовательных цифр), используйте символ + (оператор), что означает "одно или несколько вхождений предыдущего шаблона", как в sub ("[0-9]+","5") .
  • Но я вкратце остановился на проблеме ранее в этом списке.  В то время как == проверяет точное равенство полной строки, ~ "pattern" и /pattern/ test для строки, содержащей подстроку, которая соответствует шаблону.  Так, например, /TIMEOUT=[0-9]/ будет соответствовать строке, которая выглядит как
    В американском футболе время ожидания = 30 секунд
    Если с тобой все в порядке, хорошо.  Я предполагаю, что вы хотите сопоставить только целую строку, поэтому вам нужно "привязать" шаблон так, чтобы TIMEOUT был в начале строки, а число - в конце.  Вы делаете это с символами ^ и $ , как в /^TIMEOUT=[0-9]$/ .
    Кроме…
  •       … Как указано выше, [0-9] соответствует только одной цифре, так что выше будет соответствовать TIMEOUT=7 но не TIMEOUT=11 .  Вам нужно /^TIMEOUT=[0-9]+$/ .

TL; DR

Вам нужно сделать

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

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


Я призываю вас выучить awk , так как он может быть очень полезным и очень мощным.  Однако, для такой простой задачи, как эта, вы можете обойтись более простым инструментом: sed .

К сожалению, sed обычно не поддерживает оператор + (один или несколько).  В GNU sed (версии, которая поставляется с Cygwin и большинством (если не всеми) дистрибутивами Linux), вы можете указать опцию -r чтобы она распознала «расширенные регулярные выражения».  (Шаблоны типа [0-9]+ называются «регулярными выражениями».)  Так что вы могли бы сделать

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

Но некоторые (более старые) версии sed не поддерживают опцию -r и вообще не поддерживают расширенные регулярные выражения.  К счастью, вы можете обойти это: есть еще один специальный символ (оператор), *, что означает « ноль или более вхождений предыдущего шаблона».  «Одна или несколько цифр» эквивалентны «одной цифре, за которой следуют ноль или более дополнительных цифр», поэтому мы можем перевести [0-9]+ в [0-9][0-9]* и выполнить команду как

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

Вместо [0-9][0-9]* вы также можете сделать [0-9]*[0-9] (одна цифра, которой предшествует ноль или более дополнительных цифр).  Я предпочитаю вторую форму, потому что я думаю, что она выглядит более сбалансированной, но она не очень популярна.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .