使用 bash 脚本编辑文件中的某些变量
Edit certain variables in a file using bash script
下面我有以下 SES.ses
文件:
1 VERSION_CONTROL {
2 FILE_NAME = "C:/Users/kjbaili/Documents/SWCD_TEST/SES.ses";
3 DATE = "";
4 VERSION = "1.1";
5 AUTHOR = "";
6 }
7
8 DISPLAYS {
9 DISPLAY xxx-c-vm-0120:main = {
10 COMPUTER = "xxx-C-VM-0120";
11 DISPLAY = "main";
12 ITEMS {
13 PANEL {
14 name = "visu.pnl";
15 }
16 }
17 }
18 }
19
20 RT-HOSTS {
21 RT-HOST xxx-c-vm-0120 = {
22 COMPONENT {
23 name = "RTE_connections_xxxxx.cmp";
24 }
25 COMPONENT {
26 name = "xxxx.cmp";
27 }
28 }
29 RT-HOST xxx-c-agx-0003 = {
30 COMPONENT {
31 name = "CtApxxx.cmp";
32 }
33 COMPONENT {
34 name = "CtApxxx.cmp";
35 }
36 COMPONENT {
37 name = "CtApxxx.cmp";
38 }
39 }
40 }
41
42 HARDWARE {
43 }
用户输入三个 Input,分别放在 2
、9
、21
和 29
行 -> /userpath
、DISPLAY Node0
、RT-HOSTS Node0
和 RT-HOSTS Node1
。
我正在尝试根据上述用户输入编辑此文件中的变量。它们是:FILE_NAME (line 2)
、DISPLAY (line 9)
、RT-HOSTS ( line 21 and 29)
经过一些研究,我可以构建以下内容:
currentPath=$(pwd)/SES
awk -v path="$currentPath" '/FILE_NAME/ {cnt++} /FILE_NAME/ && cnt==1 {lnee=gensub(/(^.*\")(.*)(\".*$)/,"\1"path"\3",[=12=]);print lnee; next}1' SES.ses > SES.temp && mv -f SES.tmp SES.ses
此命令假定找到 FILE_NAME
的第一个条目并将变量 currentPath
设置为它。但是我收到以下错误:
awk: cmd. line:1: warning: regexp escape sequence `\"' is not a known regexp operator
mv: cannot stat 'SES.tmp': No such file or directory
所以我的问题是如何解决这个错误以及如何设置其他三个变量line 9, 21 and 29
提前致谢,非常感谢您的帮助
来自@Ed Morton 的建议解决方案:
awk -v filename='foo' -v display='bar' -v rthosts='some others' 'BEGIN { numRth = split(rthosts,rths) }
(filename != "") && ( == "FILE_NAME") { newval=filename; filename="" }
(display != "") && ( == "DISPLAY") { newval=display; display="" }
(numRth in rths) && ( == "RT-HOST") { newval=rths[++c]; delete rths[c] }
newval != "" {
oldval = ( == "=" ? : )
gsub(/^[^"]*"|"[^"]*$/,"",oldval)
pos = index([=14=],oldval)
[=14=] = substr([=14=],1,pos-1) newval substr([=14=],pos+length(oldval))
newval = ""
}
{ print }' SES.ses
cat -Ev SES.ses
的输出
$
VERSION_CONTROL {$
FILE_NAME = "/c/Users/kjbaili/Documents/DO_NOT_DELETE/SES";$
DATE = "";$
VERSION = "1.1";$
AUTHOR = "";$
}$
$
DISPLAYS {$
DISPLAY d = {$
COMPUTER = "FDT-C-VM-0120";$
DISPLAY = "main";$
ITEMS {$
PANEL {$
name = "visu.pnl";$
}$
}$
}$
}$
$
RT-HOSTS {$
RT-HOST v = {$
COMPONENT {$
name = "RTE_connections_CtCoFallbackPath.cmp";$
}$
COMPONENT {$
name = "CtGwHwpFbpCmp.cmp";$
}$
}$
RT-HOST v = {$
COMPONENT {$
name = "CtApHwpFbpSit.cmp";$
}$
COMPONENT {$
name = "CtApHwpFbpMpl.cmp";$
}$
COMPONENT {$
name = "CtApHwpFbpCVGen.cmp";$
}$
}$
}$
$
HARDWARE {$
}$
gensub()
函数的第三个参数必须是替换计数
例如 1
或 g
(全局)。
你能试试吗:
#!/bin/bash
# user's inputs
read -p "FILE_NAME: " -r file_name
read -p "DISPLAY: " -r display
read -p "RT-HOST: " -r rt_host
awk -v file_name="$file_name" -v display="$display" -v rt_host="$rt_host" '
{
sub(/FILE_NAME *= *\"[^"]+/, "FILE_NAME = \"" file_name)
sub(/DISPLAY *[^:]+:/, "DISPLAY " display ":")
}
/RT-HOST / {
if (! count++)
sub(/RT-HOST *[^[:space:]]+ *=/, "RT-HOST " display " =")
else
sub(/RT-HOST *[^[:space:]]+ *=/, "RT-HOST " rt_host " =")
}
1
' SES.ses > SES.tmp && mv -f -- SES.tmp SES.ses
如果 ed 是 available/acceptable。
这应该显示替换。
#!/usr/bin/env bash
file_name=foobar
display=barmore
rt_host=quxfux
ed -s SES.ses <<-EOF
2,/FILE_NAME/s/".\{1,\}"/"$file_name"/
9s|^\([[:blank:]]*DISPLAY\).\{1,\}\(=[[:blank:]]*{$\)| $display |
21,29s|^\([[:blank:]]*RT-HOST\).\{1,\}\(=[[:blank:]]*{$\)| $rt_host |
,p
Q
EOF
就像 @tshiono 使用内置函数 read
获取 用户的输入一样
#!/usr/bin/env bash
# user's inputs
read -p "FILE_NAME: " file_name
read -p "DISPLAY: " display
read -p "RT-HOST: " rt_host
ed -s SES.ses <<-EOF
2,/FILE_NAME/s/".\{1,\}"/"$file_name"/
9s|^\([[:blank:]]*DISPLAY\).\{1,\}\(=[[:blank:]]*{$\)| $display |
21,29s|^\([[:blank:]]*RT-HOST\).\{1,\}\(=[[:blank:]]*{$\)| $rt_host |
,p
Q
EOF
那里的 ,p
只是显示新编辑缓冲区的输出是什么,将其删除以使输出静音。
将 Q
更改为 w
以编辑 file-inplace
您收到警告(不是错误)消息 escape sequence '\"' is not a known regexp operator
因为 "
不是正则表达式元字符,它只是一个普通的旧文字字符,如 x
,但在你的正则表达式 (^.*\")(.*)(\".*$)
你写了 \"
所以要么:
- 你试图在不需要转义时转义
"
或者,
- 您正试图在您的正则表达式中包含文字
\
但是
你需要将其转义为 \
才能做到这一点。
所以无论哪种方式,您的正则表达式都有问题,所以 awk 会警告您。
我认为这可能是您想要做的:
$ cat tst.awk
BEGIN { numRth = split(rthosts,rths) }
(filename != "") && ( == "FILE_NAME") { newval=filename; filename="" }
(display != "") && ( == "DISPLAY") { newval=display; display="" }
(numRth in rths) && ( == "RT-HOST") { newval=rths[++c]; delete rths[c] }
newval != "" {
oldval = ( == "=" ? : )
gsub(/^[^"]*"|"[^"]*$/,"",oldval)
pos = index([=10=],oldval)
[=10=] = substr([=10=],1,pos-1) newval substr([=10=],pos+length(oldval))
newval = ""
}
{ print }
$ awk -v filename='foo' -v display='bar' -v rthosts='some others' -f tst.awk file
VERSION_CONTROL {
FILE_NAME = "foo";
DATE = "";
VERSION = "1.1";
AUTHOR = "";
}
DISPLAYS {
DISPLAY bar = {
COMPUTER = "xxx-C-VM-0120";
DISPLAY = "main";
ITEMS {
PANEL {
name = "visu.pnl";
}
}
}
}
RT-HOSTS {
RT-HOST some = {
COMPONENT {
name = "RTE_connections_xxxxx.cmp";
}
COMPONENT {
name = "xxxx.cmp";
}
}
RT-HOST others = {
COMPONENT {
name = "CtApxxx.cmp";
}
COMPONENT {
name = "CtApxxx.cmp";
}
COMPONENT {
name = "CtApxxx.cmp";
}
}
}
HARDWARE {
}
下面我有以下 SES.ses
文件:
1 VERSION_CONTROL {
2 FILE_NAME = "C:/Users/kjbaili/Documents/SWCD_TEST/SES.ses";
3 DATE = "";
4 VERSION = "1.1";
5 AUTHOR = "";
6 }
7
8 DISPLAYS {
9 DISPLAY xxx-c-vm-0120:main = {
10 COMPUTER = "xxx-C-VM-0120";
11 DISPLAY = "main";
12 ITEMS {
13 PANEL {
14 name = "visu.pnl";
15 }
16 }
17 }
18 }
19
20 RT-HOSTS {
21 RT-HOST xxx-c-vm-0120 = {
22 COMPONENT {
23 name = "RTE_connections_xxxxx.cmp";
24 }
25 COMPONENT {
26 name = "xxxx.cmp";
27 }
28 }
29 RT-HOST xxx-c-agx-0003 = {
30 COMPONENT {
31 name = "CtApxxx.cmp";
32 }
33 COMPONENT {
34 name = "CtApxxx.cmp";
35 }
36 COMPONENT {
37 name = "CtApxxx.cmp";
38 }
39 }
40 }
41
42 HARDWARE {
43 }
用户输入三个 Input,分别放在 2
、9
、21
和 29
行 -> /userpath
、DISPLAY Node0
、RT-HOSTS Node0
和 RT-HOSTS Node1
。
我正在尝试根据上述用户输入编辑此文件中的变量。它们是:FILE_NAME (line 2)
、DISPLAY (line 9)
、RT-HOSTS ( line 21 and 29)
经过一些研究,我可以构建以下内容:
currentPath=$(pwd)/SES
awk -v path="$currentPath" '/FILE_NAME/ {cnt++} /FILE_NAME/ && cnt==1 {lnee=gensub(/(^.*\")(.*)(\".*$)/,"\1"path"\3",[=12=]);print lnee; next}1' SES.ses > SES.temp && mv -f SES.tmp SES.ses
此命令假定找到 FILE_NAME
的第一个条目并将变量 currentPath
设置为它。但是我收到以下错误:
awk: cmd. line:1: warning: regexp escape sequence `\"' is not a known regexp operator
mv: cannot stat 'SES.tmp': No such file or directory
所以我的问题是如何解决这个错误以及如何设置其他三个变量line 9, 21 and 29
提前致谢,非常感谢您的帮助
来自@Ed Morton 的建议解决方案:
awk -v filename='foo' -v display='bar' -v rthosts='some others' 'BEGIN { numRth = split(rthosts,rths) }
(filename != "") && ( == "FILE_NAME") { newval=filename; filename="" }
(display != "") && ( == "DISPLAY") { newval=display; display="" }
(numRth in rths) && ( == "RT-HOST") { newval=rths[++c]; delete rths[c] }
newval != "" {
oldval = ( == "=" ? : )
gsub(/^[^"]*"|"[^"]*$/,"",oldval)
pos = index([=14=],oldval)
[=14=] = substr([=14=],1,pos-1) newval substr([=14=],pos+length(oldval))
newval = ""
}
{ print }' SES.ses
cat -Ev SES.ses
$
VERSION_CONTROL {$
FILE_NAME = "/c/Users/kjbaili/Documents/DO_NOT_DELETE/SES";$
DATE = "";$
VERSION = "1.1";$
AUTHOR = "";$
}$
$
DISPLAYS {$
DISPLAY d = {$
COMPUTER = "FDT-C-VM-0120";$
DISPLAY = "main";$
ITEMS {$
PANEL {$
name = "visu.pnl";$
}$
}$
}$
}$
$
RT-HOSTS {$
RT-HOST v = {$
COMPONENT {$
name = "RTE_connections_CtCoFallbackPath.cmp";$
}$
COMPONENT {$
name = "CtGwHwpFbpCmp.cmp";$
}$
}$
RT-HOST v = {$
COMPONENT {$
name = "CtApHwpFbpSit.cmp";$
}$
COMPONENT {$
name = "CtApHwpFbpMpl.cmp";$
}$
COMPONENT {$
name = "CtApHwpFbpCVGen.cmp";$
}$
}$
}$
$
HARDWARE {$
}$
gensub()
函数的第三个参数必须是替换计数
例如 1
或 g
(全局)。
你能试试吗:
#!/bin/bash
# user's inputs
read -p "FILE_NAME: " -r file_name
read -p "DISPLAY: " -r display
read -p "RT-HOST: " -r rt_host
awk -v file_name="$file_name" -v display="$display" -v rt_host="$rt_host" '
{
sub(/FILE_NAME *= *\"[^"]+/, "FILE_NAME = \"" file_name)
sub(/DISPLAY *[^:]+:/, "DISPLAY " display ":")
}
/RT-HOST / {
if (! count++)
sub(/RT-HOST *[^[:space:]]+ *=/, "RT-HOST " display " =")
else
sub(/RT-HOST *[^[:space:]]+ *=/, "RT-HOST " rt_host " =")
}
1
' SES.ses > SES.tmp && mv -f -- SES.tmp SES.ses
如果 ed 是 available/acceptable。
这应该显示替换。
#!/usr/bin/env bash
file_name=foobar
display=barmore
rt_host=quxfux
ed -s SES.ses <<-EOF
2,/FILE_NAME/s/".\{1,\}"/"$file_name"/
9s|^\([[:blank:]]*DISPLAY\).\{1,\}\(=[[:blank:]]*{$\)| $display |
21,29s|^\([[:blank:]]*RT-HOST\).\{1,\}\(=[[:blank:]]*{$\)| $rt_host |
,p
Q
EOF
就像 @tshiono 使用内置函数 read
获取 用户的输入一样
#!/usr/bin/env bash
# user's inputs
read -p "FILE_NAME: " file_name
read -p "DISPLAY: " display
read -p "RT-HOST: " rt_host
ed -s SES.ses <<-EOF
2,/FILE_NAME/s/".\{1,\}"/"$file_name"/
9s|^\([[:blank:]]*DISPLAY\).\{1,\}\(=[[:blank:]]*{$\)| $display |
21,29s|^\([[:blank:]]*RT-HOST\).\{1,\}\(=[[:blank:]]*{$\)| $rt_host |
,p
Q
EOF
那里的 ,p
只是显示新编辑缓冲区的输出是什么,将其删除以使输出静音。
将 Q
更改为 w
以编辑 file-inplace
您收到警告(不是错误)消息 escape sequence '\"' is not a known regexp operator
因为 "
不是正则表达式元字符,它只是一个普通的旧文字字符,如 x
,但在你的正则表达式 (^.*\")(.*)(\".*$)
你写了 \"
所以要么:
- 你试图在不需要转义时转义
"
或者, - 您正试图在您的正则表达式中包含文字
\
但是 你需要将其转义为\
才能做到这一点。
所以无论哪种方式,您的正则表达式都有问题,所以 awk 会警告您。
我认为这可能是您想要做的:
$ cat tst.awk
BEGIN { numRth = split(rthosts,rths) }
(filename != "") && ( == "FILE_NAME") { newval=filename; filename="" }
(display != "") && ( == "DISPLAY") { newval=display; display="" }
(numRth in rths) && ( == "RT-HOST") { newval=rths[++c]; delete rths[c] }
newval != "" {
oldval = ( == "=" ? : )
gsub(/^[^"]*"|"[^"]*$/,"",oldval)
pos = index([=10=],oldval)
[=10=] = substr([=10=],1,pos-1) newval substr([=10=],pos+length(oldval))
newval = ""
}
{ print }
$ awk -v filename='foo' -v display='bar' -v rthosts='some others' -f tst.awk file
VERSION_CONTROL {
FILE_NAME = "foo";
DATE = "";
VERSION = "1.1";
AUTHOR = "";
}
DISPLAYS {
DISPLAY bar = {
COMPUTER = "xxx-C-VM-0120";
DISPLAY = "main";
ITEMS {
PANEL {
name = "visu.pnl";
}
}
}
}
RT-HOSTS {
RT-HOST some = {
COMPONENT {
name = "RTE_connections_xxxxx.cmp";
}
COMPONENT {
name = "xxxx.cmp";
}
}
RT-HOST others = {
COMPONENT {
name = "CtApxxx.cmp";
}
COMPONENT {
name = "CtApxxx.cmp";
}
COMPONENT {
name = "CtApxxx.cmp";
}
}
}
HARDWARE {
}