awk 系统调用 Linux - 从 awk 调用 shell 时使用扩展正则表达式

awk 系统调用 Linux - 从 awk 调用 shell 时使用扩展正则表达式

能够从 awk 调用系统命令非常有用。但是,如果您尝试使用 shell 扩展正则表达式,您会发现它不起作用。

这是因为 awk 调用 /bin/sh 而不是您现在在 Linux 中所期望的 /bin/bash。

从 awk 调用系统时,如何使扩展的正则表达式起作用?

答案1

我不明白为什么当 awk 完全有能力时你需要在 bash 中做这么多事情:

BEGIN {
    filename[0]="/media/Pan/test-data/The_long_file.gz";
    filename[1]="/media/Pan/test-data/The_long_file";

    for (n=0; n<2; n++) {
        print "Contents  of file: " filename[n];

        if (filename[n] ~ /\.gz$/) {
            command = "gunzip --to-stdout " filename[n]
            while (( command | getline file_contents ) > 0 ) {
                print file_contents
            }
            close(command)
        }
        else {
            while (( getline line < filename[n]) > 0 ) {
                print line
            }
        }
    }
}

答案2

能够从 awk 调用系统命令非常有用。但是,如果您尝试使用 shell 扩展正则表达式,您会发现它不起作用。

这是因为 awk 调用 /bin/sh 而不是您现在在 Linux 中所期望的 /bin/bash。

有一个不太混乱的解决方案。如果您需要从各种文件中读取信息,其中一些文件是压缩的,另一些则不是,您可以在 awk 中使用扩展正则表达式,如下所示:

BEGIN   {
        filename[0]="/media/Pan/test-data/The_long_file.gz";
        filename[1]="/media/Pan/test-data/The_long_file";
        for ( n=0;n<2;n++)
                {
                print "Contents  of file: " filename[n];
                command="exec /bin/bash -c \"[[ \"" filename[n] "\" =~ .gz ]] \
                &&gunzip --to-stdout " filename[n] "\
                ||cat " filename[n] "\"";
                while (( command | getline file_contents ) > 0 )
                        print file_contents;
                }
        }

此示例列出了同一文件 /media/Pan/test-data/The_long_file 的内容两次,一次为压缩版本,一次为纯文本。

要测试上述内容,请将其复制到 test.awk,创建两个文件,一个压缩,一个未压缩,并将它们的名称放入 filename[0] 和 [1] 中,然后运行它:

awk -f test.awk </dev/null

我知道,这个例子本身并不是很有用,但是转义字符和引号都在正确的位置,并且用 /bin/bash 替换 /bin/sh 是有效的。

我希望这能节省一些人获得正确语法所花费的时间。

上面的代码通过使用exec替换/bin/sh解决了awk调用/bin/sh引起的问题。传递到 shell 的代码是:

 exec /bin/bash -c "[[ \"filename\" =~ .gz ]] &&gunzip --to-stdout filename ||cat filename"

bash执行的代码是:

 [[ "filename" =~ .gz ]] &&gunzip --to-stdout filename ||cat filename

上面的扩展正则表达式检查“文件名”是否与表达式“.gz”匹配。如果是,它将执行gunzip。如果没有,它只会捕获该文件。您可以通过替换“.”来改进正则表达式。与“.”,所以它只匹配一个“.”,并添加一个“$”,所以它只匹配行尾的它 - 我没有这样做是为了保持清晰度。

相关内容