我是学习的新手awk
。
我有一个文件,其中包含以下行以及其他行:
TIMEOUT=200
我需要更改数值。
仅当我事先知道该值时,此命令才能更改该值:
awk '$0 == "TIMEOUT=200" { sub ("200","5") } { print }' file
如果我不知道该值,我应该使用什么命令?
像这样:
awk '$0 == "TIMEOUT=[0-9]" { sub ("[0-9]","5") } { print }' file
但是我尝试了该命令,它并没有改变任何东西。
答案1
- 您的尝试不起作用,因为
==
仅测试完全相等。如果您的文件包含一行,确切地说是,TIMEOUT=[0-9]
您的代码会识别它(并将其更改为TIMEOUT=[5-9]
)。但是,正如您所见,它与像这样的字符串不匹配TIMEOUT=42
。您当然希望选择与模式匹配的行。一种方法是使用TIMEOUT=number
~
运算符代替==
:awk'$0~"超时=[0-9]" {行动声明}'
- 了解如何使用
~
运算符,并知道您可以对单个字段进行测试。但是,有一种简写符号可以将整行与模式进行匹配:awk'/TIMEOUT=[0-9]/{行动声明}'
当你能够使用它的时候,你也许会想使用它。 - 所以现在如果我们这样做
awk'/TIMEOUT=[0-9]/{sub(“[0-9]”,“5”)}{打印}'
它将匹配TIMEOUT=200
行 — 并将其更改为TIMEOUT=500
,因为[0-9]
仅匹配单个数字(数字),而不是多位数字。要查找(并替换)多位数字(一个或多个连续数字的字符串),请使用+
字符(运算符),表示“前一个模式出现一次或多次”,如sub ("[0-9]+","5")
。 - 但我在前面的列表中忽略了一个问题。虽然
==
测试完全的字符串, 并 测试包含与模式匹配的子字符串的字符串。例如, 将匹配如下行~ "pattern"
/pattern/
/TIMEOUT=[0-9]/
在美式足球中,暂停=30秒
如果你觉得可以,那就好了。我猜你只想匹配一整行,所以你会想“锚定”模式,这样TIMEOUT
必须位于行首,数字必须位于行尾。你可以使用^
和$
字符来执行此操作,例如。/^TIMEOUT=[0-9]$/
除了… - …如前所述,
[0-9]
仅匹配一位数字,因此上面的内容将匹配TIMEOUT=7
但不会匹配TIMEOUT=11
。您需要。/^TIMEOUT=[0-9]+$/
总结
你需要做
awk ‘$0 ~ “^TIMEOUT=[0-9]+$” { sub (“[0-9]+”,“5”) } { 打印 }’ 文件或者
awk ‘/^TIMEOUT=[0-9]+$/ { sub (“[0-9]+”,“5”) } { 打印 }’ 文件
我鼓励您学习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]
(一位数字,先于零个或多个附加数字)。我更喜欢第二种形式,因为我认为它看起来更平衡,但它并不是很流行。