【问题标题】:AWK add line below a search pattern with variable and in a shell scriptAWK 在带有变量的搜索模式下方和 shell 脚本中添加行
【发布时间】:2015-10-17 06:24:17
【问题描述】:

在 shell 脚本中使用 awk 行有一点问题,我找不到我犯的错误。希望,任何人都可以帮助我。

我使用 awk 版本 20070501 和 Mac。

我正在使用以下代码在指定模式下添加一行:

...

ANSHOSTGROUPS=($(egrep "^\[.*\]$" hosts))
INSERT="dc01.fritz.box ansible_ssh_host=192.168.4.27"
...
awk -v INSERT=$INSERT "/${ANSHOSTGROUPS[2]}/{print \$1;print INSERT;next}1" hosts > /tmp/tmp_hosts && mv -f /tmp/tmp_hosts hosts

我在文件“hosts”中得到以下内容:

[test]
centos7-test.fritz.box

[lab]
dc01.fritz.box ansible_ssh_host=192.168.4.27

[ldap]
dc01.fritz.box ansible_ssh_host=192.168.4.27

[mysql]
dc01.fritz.box ansible_ssh_host=192.168.4.27

现在,当我直接在命令行上使用以下内容进行测试时:

awk -v INSERT="dc01.fritz.box ansible_ssh_host=192.168.4.27" "/\[ldap\]/{print \$1;print INSERT;next}1" hosts

我正确理解

[test]
centos7-test.fritz.box

[lab]

[ldap]
dc01.fritz.box ansible_ssh_host=192.168.4.27

[mysql]

感谢大家的帮助!

--- 由于评论栏太小,在此编辑

好的,我使用问题中的文件内容来构建变量。 我现在用过

ANSHOSTGROUPS=($(egrep "^\[.*\]$" hosts |sed 's/\[/\\\[/g' |sed 's/\]/\\\]/g'))

或者直接使用

ANSHOSTGROUPS=(\[test\] \[lab\] \[ldap\] \[mysql\])

用于测试,无需先构建文件。

现在变量显示如下:

echo ${ANSHOSTGROUPS[@]}
\[test\] \[lab\] \[ldap\] \[mysql\]

接下来我尝试使用您的线路:awk -v anshostgroup="${ANSHOSTGROUPS[2]}" -v insert="dc01.fritz.box ansible_ssh_host=192.168.4.27" '$0 ~ anshostgroup{$0=$1 ORS insert}1' hosts

之后,我得到了与我在问题中写的相同的错误输出。我还尝试在没有两个管道和 sed 的情况下构建变量。但同样的输出。

【问题讨论】:

  • 您正在尝试在 awk ${ANSHOSTGROUPS[2] 中使用 shell 变量
  • 当你使用bash -x yourscript.sh时你看到了什么?具体来说,是否将正确的值代入awk 脚本?手动代码在正则表达式元字符[ 前面有一个反斜杠(] 前面有一个不太重要的反斜杠)。您的 awk 脚本没有这种保护;它只查找包含来自[ldap] 的任何字母的行(因此a d l 一个p)。至少,您需要将\\${ANSHOSTGROUPS[2]} 放入awk 脚本中。这可能就足够了。
  • 我现在正在工作。我会在晚上检查,但你是对的。可能是 [ 。似乎合乎逻辑。我看看能不能把括号从变量中取出来。
  • 嘿乔纳森,在你的帮助下我找到了错误。我刚刚将 ANSHOSTGROUPS=($(egrep "^\[.*\]$" hosts)) 更改为 ANSHOSTGROUPS=($(egrep "^\[.*\]$" hosts |sed 's/\[/\\\[/g' |sed 's/\]/\\\]/g')) 。正如您所说,awk 使用 [] 中的字母作为正则表达式。非常感谢!

标签: macos bash shell awk


【解决方案1】:

您在答案中包含的 awk 脚本应该是:

awk -v insert="$INSERT" -v anshostgroup="${ANSHOSTGROUPS[2]}" '$0 ~ anshostgroup{$0=$1 ORS insert}1' hosts > /tmp/tmp_hosts && mv -f /tmp/tmp_hosts hosts

我将您的 awk 变量名称更改为小写,因为全大写用于内置名称,例如 FSRS。按照惯例,您不应该使用全大写的 shell 名称,这仅适用于导出的变量。

如果您发布了一些可测试的示例输入和预期输出,我们也可以帮助您正确完成脚本的其余部分(您不需要 grep+sed+2 管道,但没有看到示例输入,我不会尝试找出尝试解析它的正确方法!)。

【讨论】:

  • 感谢您迄今为止的帮助。我仍在学习并很高兴获得任何帮助。我来测试一下。
【解决方案2】:

以下代码现在可以在 shell 脚本中运行。感谢乔纳森·莱弗勒!!

...

ANSHOSTGROUPS=($(egrep "^\[.*\]$" hosts |sed 's/\[/\\\[/g' |sed 's/\]/\\\]/g'))
INSERT="dc01.fritz.box ansible_ssh_host=192.168.4.27"
...
awk -v INSERT=$INSERT "/${ANSHOSTGROUPS[2]}/{print \$1;print INSERT;next}1" hosts > /tmp/tmp_hosts && mv -f /tmp/tmp_hosts hosts

以防万一有人对使用或修改它的完整脚本感兴趣:https://github.com/matze502/scripts/tree/master/bash/vmware/fusion

我使用脚本自动克隆一个 vm 以供实验室使用 vmware fusion。

【讨论】:

  • 这绝对不是怎么做的,因为它会使你的 awk 脚本复杂化,因为它需要逃避 $ 标志等,并为奇怪的失败和/或错误消息创造各种机会,因为你正在制作awk 脚本文本的 shell 变量部分的内容,而不是将 awk 变量设置为 shell 变量的内容。
  • 很抱歉,如果您有更好的想法让它发挥作用,那么我愿意为所有人服务。我刚刚发现这是我完成这项任务的唯一方法。也许我也可以使用-v ANSHOSTGROUPS=${ANSHOSTGROUPS[2]}
  • 我刚刚发布了脚本那部分的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多