如何编写 awk 脚本?

如何编写 awk 脚本?

我想弄清楚如何编写独立的 awk 脚本文件。

我认为它类似于独立的 bash 脚本文件:

#! /usr/bin/awk -f      
BEGIN{
    for  (i  =  0;  i  <  ARGC;  i++)
        printf  "%s  ",  ARGV[i]
    printf  "\n"
}
{print $0}
  1. 我试图弄清楚如何在 shell 中指定命令行参数并将其传递到脚本中:

    $ myscript.awk arg1 arg2 arg3
    awk  arg1  arg2  arg3  
    awk: /home/tim/myscript.awk:5: fatal: cannot open file `arg1' for reading (No such file or directory)
    

    awk 脚本期望其命令行参数是什么?为什么它期望arg1 成为输入文件?

    命令行参数被传递到 awk 脚本中,并存储在数组 ARGV 中。看我的更新。所以我想命令行参数是根据脚本解释的,而不是awk.

  2. 如果我删除-fshebang,即#! /usr/bin/awk

    $ myscript.awk arg1 arg2 arg3
    awk: cmd. line:1: /home/tim/myscript.awk
    awk: cmd. line:1:                   ^ syntax error
    

    为什么是-f必要的?

谢谢。

答案1

AWK 期望其参数是脚本的文本,或者-f后跟包含要运行的脚本的文件的名称,在这两种情况下都可以选择后跟要处理的文件的名称。

这解释了为什么您需要-f在 shebang 行中:没有它,AWK 会认为您的脚本的文件名本身就是要运行的 AWK 语句。

关于参数处理,AWK 程序可以根据需要进行自己的参数处理。您的脚本因该{print $0}行而失败:这指示解释器从其输入(命令行上命名的文件,因为您已经指定了一些文件)中读取每一行,并根据块中的说明对其进行处理。如果删除该行,则不会出现任何错误。您可以处理参数BEGIN并进行清理ARGV,使其仅包含输入文件;那么 AWK 就不会抱怨了。

尝试完全进行自己的参数和输入处理,可能意味着忽略 AWK 如此有用的许多因素;如果你想这样做,你不妨使用 Perl。

(请注意,shebang 处理意味着您可以在其文件名中存储简单的 AWK 脚本,这避免了必须为脚本找到巧妙的名称 - 并不是任何人都应该这样做......)

答案2

awk 脚本期望其命令行参数是什么?为什么它期望 arg1 作为输入文件?

awk基于模式的规则需要输入。当程序的这部分处理开始时,awk开始使用参数作为文件名(如果没有给出文件名,则使用标准输入)。

在此步骤之前,您可以使用块中给定的参数执行任何操作BEGIN

我认为,这些小例子可以帮助您入门:

$ cat a.awk 
#!/usr/bin/awk -f
BEGIN {
        i=1
        while( i in ARGV )
                print ARGV[i++]
}

a.awk只有一个BEGIN块,没有基于模式的规则。awk不需要文件,因此不使用给定的参数作为文件名:

$ ./a.awk poit --zort -troz narf
poit
--zort
-troz
narf

如何处理这些是您的决定。

如果您也希望基于模式的规则处理作为参数给出的文件,则需要删除块中使用的所有参数BEGIN

$ cat b.awk 
#!/usr/bin/awk -f
BEGIN {
        if( ARGV[1] == "--tolower" ) { cmd = "tr A-Z a-z" ; delete ARGV[1] }
        else if( ARGV[1] == "--toupper" ) { cmd = "tr a-z A-Z" ; delete ARGV[1] }
        else cmd = "cat"
}
{
        print | cmd
}

不带选项运行示例:

$ ./b.awk a.awk
#!/usr/bin/awk -f
BEGIN {
        i=1
        while( i in ARGV )
                print ARGV[i++]
}

使用--toupper选项运行示例:

$ ./b.awk --toupper a.awk
#!/USR/BIN/AWK -F
BEGIN {
        I=1
        WHILE( I IN ARGV )
                PRINT ARGV[I++]
}

答案3

脚本awk期望其非选项命令行参数是脚本应执行操作的文件的文件名(如果没有给出,则它对标准输入执行操作)。

因此,当您#!/usr/bin/awk -fawk脚本文件中使用时,这会告诉系统文件本身的文本应该传递到awk -f.任何其他命令行参数将被解释为输入文件或附加标志awk

#!/usr/bin/awk -f

BEGIN {
    for (i in ARGV) {
        printf("ARGV[%d] = %s\n", i, ARGV[i]);
    }
    printf("var = %s\n", var);
}

$ ./script.awk -vvar=hello ~/.profile
ARGV[0] = awk
ARGV[1] = /home/kk/.profile
var = hello

命令行检查选项在第一个非选项参数处结束:

$ ./script.awk ~/.profile -vvar=hello
ARGV[2] = -vvar=hello
ARGV[0] = awk
ARGV[1] = /home/kk/.profile
var =

为了awk对任何事情有用,它需要输入数据。该数据通常来自命令行上命名的一个或多个输入文件,或者来自标准输入流上发送的数据。

除了BEGINEND块之外,脚本中的每个块awk将依次应用于输入数据的每条记录(默认为每行)。

相关内容