Awk 追加到数组以进行进一步处理

Awk to append out to array for further processing

希望在我目前的 bash 技能无法计算的事情上动脑筋;)

正在解析一个 named.conf 文件以引用实际区域文件的文件名,我想将其复制到一个目录以用于迁移目的。第一步,我想到将区域文件的路径作为 awk 操作的一部分放入一个数组中。从最初的解析循环中出来,然后我可以遍历数组查找新的引用(到下面的 .db 文件)并复制文件。最终,作为区域文件副本的一部分,我希望通过引用域名来重命名目标文件(例如 domaina.com)。

所以,我创建了一个包含域的输入文件,例如:

cat domains.txt
domaina.com
domainb.com
domainc.com

named.conf.deployed 将包含每个相关域的一部分(如下所示)。

// zone: domaina.com [slave]
include "/etc/active/1704500.conf";

现在,回到我到目前为止所取得的成就 - 这并不多 :( 如您所知,该脚本仅设法解析文件并打印 [=39= 中包含的区域的路径] 文件。

while read p; do
grep -A2 "$p" /jail/named/etc/named.conf.deployed | grep include | awk -F\" '{print $(NF-1)}'
done <domains.txt

以上脚本的输出为:

/etc/active/1704500.conf

我可以通过展开 awk 语句来追加到数组中,而不是打印结果吗?或者正如@David 建议我们输出的 tmp 文件。下一步将是打开文件(例如 /etc/active/1704500.conf)并进行类似的解析,因为我真正想要的文件被埋在 .conf 文件中(请参阅下面的内容 1704500.conf)。

// zone: domaina.com
zone "domaina.com"
{
type slave;
file "4725680.db";
};

最后,复制(在上面的示例中)4725680.db 文件并将其重命名为 domaina.com。这就是我希望在下一个循环或代码块中完成的目标。

干杯, 弗雷德里克

请原谅我所有的编辑,这是新手,需要学习(快速)如何解释和传递有关我的挑战的足够信息。

我觉得你的问题很难理解,但我认为这就是你的意思:

arr=()             # empty array
arr+=('foo')       # add new element
arr+=('bar')       # add new element
echo ${arr[@]}     # print what we've got
foo bar

# add new elements from awk command
arr+=($(awk -F: 'NR>10 && NR<14 {print }' /etc/passwd))

# see what we have now
echo ${arr[@]}
foo bar nobody root daemon

你在 greppingawking?耻辱,耻辱...

您可以删除链,并使用 awk 查找您正在使用 grep 执行的行:

$ grep "foo"  | awk '{print }'
$ awk '/foo/ {print }'

做同样的事情。 awk 可以像 grep 一样 grep 输出行。

你的解释和例子离你想做的有点短。我认为您想保留 etc/active/1704500.conf 并将其与 domaina.com 相关联。也就是说,您需要一个 关联数组 。对吗?

尽管许多人将 awk 视为 cut 的另一个版本,但它本身确实是一种编程语言。 Awk 假设有一个循环,您将程序放入该循环中。 awk 还有一个 BEGINEND 子句来进行预循环和 post 循环处理。

您可能想要做的,不是在 Awk 中创建数组,而是让您的 awk 程序打印出您想要的两个字段,然后您可以在另一个循环中处理它们:

while read p
do
     awk '.......' >> awk.temp.$$
done
while read domain file
do
    ....
done < awk.temp.$$
rm awk.temp.$$

awk 程序看起来像这样:

awk  '
    /\/\/ zone:/  {
    machine = 
    getline
    file = substr( , 2, length () - 3 )
    print machine  " " file
}' test.txt

/\/\/ zone:/ 正在查找该正则表达式。我将该字符串的第三个字段保存到变量 machinegetline 让我进入下一行。然后我使用 substrlength 来获取第二个单词(这是用引号括起来的文件名),然后去掉开头的引号和结尾的 quote/semicolon.

Awk 不是 shell 的一部分,因此 Awk 中的变量不会在 awk 程序的上下文之外继续存在。在 Awk 中创建数组没有帮助。

我的系统上只有 Bash 3.2,所以我没有 Bash 4 中的关联数组。但是,也许可以在 Awk 中操作输出以允许您使用它来创建关联数组。

我不是 100% 确定,我无法对此进行测试,但您可以这样做:

awk  '
    BEGIN { printf "(" }
    END   { print ")" }
    /\/\/ zone:/  {
    machine = 
    getline
    file = substr( , 2, length () - 3 )
    printf "[" machine "]=" file " "
}' test.txt

awk 会输出如下内容:

([machine]=/etc/file [machine2]=/etc/file2)

然后可用于初始化 shell 关联数组。

在 awk 中做所有事情要简单得多(假设我理解问题)。

$ cat domains.txt
domaina.com
domainb.com
domainc.com


$ cat named.conf.deployed
// zone: domaina.com [slave]
include "/etc/active/1704500.conf";

// zone: domainx.com [slave]
include "/etc/active/XXXX.conf";

// zone: domainc.com [slave]
include "/etc/active/CCCCC.conf";

// zone: domainb.com [slave]
include "/etc/active/BBBB.conf";


$ cat domconf.awk
NR == FNR { domains[]; next }

 == "zone:" { flag = ( in domains) }

 == "include" && flag { print clean(); flag = 0 }

function clean(s) {
    gsub("\";?", "", s)
    return s
}


$ awk -f domconf.awk domains.txt named.conf.deployed
/etc/active/1704500.conf
/etc/active/CCCCC.conf
/etc/active/BBBB.conf

NR == FNR { domains[]; next }

NR == FNR 表示我们正在读取第一个文件。将域读入 awk 数组。 next 跳过下面的操作并立即读取下一个域。

== "zone:" { flag = ( in domains) }

(到达此处意味着我们正在读取第二个文件。)如果是 "zone" 评论,请检查域的数组。

== "include" && flag { print clean(); flag = 0 }

如果找到域,打印包含名称(删除引号)并重置标志。

编辑
在输出中包含域名:

$ cat domconf.awk
NR == FNR { domains[]; next }

 == "zone:" { prev_domain = ; flag = ( in domains) }

 == "include" && flag { print prev_domain, clean(); flag = 0 }

function clean(s) {
    gsub("\";?", "", s)
    return s
}

$ awk -f domconf.awk domains.txt named.conf.deployed
domaina.com /etc/active/1704500.conf
domainc.com /etc/active/CCCCC.conf
domainb.com /etc/active/BBBB.conf