使用 AWK 和 gsub 查找/替换配置文件中的设置

daz*_*azz 1 bash awk gsub

我正在尝试做一些应该简单且常规的事情。\n我想搜索文件 /etc/dhcpcd.conf 并更改分配给 eth0 的未注释的静态 IP 地址。示例测试文件如下所示:

\n
interface eth0\n# test variants of comments\n#static ip_address=192.168.21.40/24\n# static ip_address=192.168.21.40/24\n #static ip_address=192.168.21.40/24\n # static ip_address=192.168.21.40/24\n\n#the line to match and change\nstatic ip_address=123.223.122.005/24\n
Run Code Online (Sandbox Code Playgroud)\n

我尝试在这里实现一个解决方案: \n这里\xe2\x80\x99s 是一种在 awk 中执行此操作的不那么神秘的方法,由 Scott 回答 - \xd0\xa1\xd0\xbb\xd0\xb0\xd0\xb2\ xd0\xb0\xd0\xa3\xd0\xba\xd1\x80\xd0\xb0\xd1\x97\xd0\xbd\xd1\x96

\n

我选择 AWK 解决方案是因为它很容易阅读,但是我无法修改答案以适合我。我之前没有使用过sedawk所以我写了一个测试脚本。

\n
#!/bin/bash\n# testing on a copy of the config file\nconf_file="/home/user/dhcpcd.conf"\n# BASH variable with fake test ip\nnew_ip=111.222.123.234\n\ncat "$conf_file" |  awk $\'\n   /interface /                    { matched=0 }\n   /interface eth0/                { matched=1 }\n    matched                        { gsub( "^\\\\s*static ip_address=\xe2\x80\xa2*" , "static ip_address=111.222.123.234" ) }\n                                   { print }\n   \'\n
Run Code Online (Sandbox Code Playgroud)\n

此 AWK 脚本用于查找该eth0节,然后查找static ip_address=任何文本。\n并将其替换为static ip_address=111.222.123.234. #注释行除外。为了进行测试,我已将测试新 IP 硬编码到 AWK 脚本中。我想使用变量 $new_ip。

\n

最初遇到了 gsub 函数的问题。\xe2\x80\xa2*匹配任何文本的意图引起了问题,因为我开始使用.*. 该手册说 gsub 使用该字符\xe2\x80\xa2而不是句号,.而没有实际强调使用 的需要Alt-7。我花了一段时间才找到这个问题,但现在问题已经解决了。

\n

我现在遇到的第一个问题是新的 ip 被插入到该行中,而不是替换旧的 ip。输出是:\n static ip_address=111.222.123.234123.223.122.005/24\n所以正则表达式是或者应该是匹配整行,包括要替换的旧 ip,但事实并非如此。

\n

我遇到的第二个问题是我需要awk使用 bash 变量new_ip。我已经查看和搜索过,但找不到有效的答案。

\n

我认为这应该有效:

\n
cat /home/mimir/dhcpcd.conf |  awk -v sip=$new_ip  $\'\n   /interface /                    { matched=0 }\n   /interface eth0/                { matched=1 }\n    matched                        { gsub( "^[:blank:]*static ip_address=\xe2\x80\xa2*" , "static ip_address=sip" ) }\n                                   { print }\n\n \'\n
Run Code Online (Sandbox Code Playgroud)\n

但事实并非如此。输出是

\n

static ip_address=sip123.223.122.005/24所以 awk 无法识别sip为变量。我做错了什么,但我看不到它。做这么简单的事情不应该那么困难。

\n

任何帮助将非常感激。

\n

编辑 No.2:\n为了那些登陆此处寻找解决方案的人的利益,这是我的工作测试脚本:

\n
 #!/bin/bash\n#  Test reading and setting of the ip address in /etc/dhcpcd.conf  using AWK\n\n# source /etc/dhcpcd.conf  which always includes the lines:\n# interface eth0\n#  static ip_address=www.xxx.yyy.zzz\n# copy of config file for testing\ncfg_file="/home/user/dhcpcd.conf"\n# fake test ip\nnew_ip="114.113.112.111"\n\nawk -i inplace -v sip=$new_ip  $\'\n   /interface /                    { matched=0 }\n   /interface eth0/                { matched=1 }\n    matched                        { gsub( "^[[:blank:]]*static ip_address=.*" , "static ip_address="sip ) }\n                                   { print }\n   \' $cfg_file\nexit\n
Run Code Online (Sandbox Code Playgroud)\n

由于下面评论中收到的建议的综合作用,现在该方法正在发挥作用。这是一个答案,但不是我的答案。它有效,但并不完美。

\n

这有一些限制。要获得技术上更好的答案,请参阅下面 Ed Morton 的答案。

\n

Ed *_*ton 5

使用任何 POSIX awk:

$ cat tst.sh
#!/usr/bin/env bash

new_ip=111.222.123.234

awk -v sip="$new_ip" '
    $1 == "interface" {
        gotIface = ($2 == "eth0" ? 1 : 0)
    }
    gotIface && match($0,/^[[:space:]]*static[[:space:]]+ip_address=/) {
        $0 = substr($0,1,RSTART+RLENGTH-1) sip
    }
    { print }
' file
Run Code Online (Sandbox Code Playgroud)

$ ./tst.sh
interface eth0
# test variants of comments
#static ip_address=192.168.21.40/24
# static ip_address=192.168.21.40/24
 #static ip_address=192.168.21.40/24
 # static ip_address=192.168.21.40/24

#the line to match and change
static ip_address=111.222.123.234
Run Code Online (Sandbox Code Playgroud)

关于:

它需要读取和写入同一个文件

GNU awk 已经做到-i inplace了这一点(但它仍然在幕后使用临时文件),但对于任何 Unix 工具,tool您可以这样做:

tmp=$(mktemp) &&
tool file > "$tmp" &&
mv -- "$tmp" file
Run Code Online (Sandbox Code Playgroud)

例如

tmp=$(mktemp) &&
awk '{print FILENAME, $0}' file > "$tmp" &&
mv -- "$tmp" file
Run Code Online (Sandbox Code Playgroud)

会在每个输入行前面添加文件名并将结果写回输入文件。