101. getline 命令


如您所知,awk 脚本的主体块对输入文件中的每一行执行一次。您无法对其进行任何控制,因为 awk 会自动进行控制。

但是,使用 getline 命令,您可以控制从输入文件(或其他文件)中读取行。 请注意,执行 getline 后,awk 脚本会相应地设置 NF NR FNR $0 内置变量的值。

$ awk -F"," '{getline; print $0;}' items.txt
102,Refrigerator,Appliance,850,2
104,Tennis Racket,Sports,190,20
105,Laser Printer,Office,475,5

当您仅在主体块中指定 getline 时,awk 会从输入文件中读取下一行。 在此示例中,bod 块中的第一个语句是 getline 。 因此,即使 awk 已经从输入文件中读取了第一行, getline 也会读取下一行,因为我们明确地从输入文件中请求下一行。 因此,在 getline 之后执行 'print $0' 会使 awk 打印第二行。

下面是它的工作原理:

  • 在主体块的开头,在执行任何语句之前,awk 读取 「items.txt」 的第一行并将其存储在 $0
  • getline - 我们强制 awk 从输入文件中读取下一行并将其存储在内置的 $0 变量中。
  • print $0 - 由于第 2 行被读入 $0 ,因此 print $0 将打印第 2 行(而不是第 1 行)。
  • 主体块以相同的方式继续处理 「items.txt」 中的其余行,并且仅打印偶数行。

您还可以将输入文件中的下一行获取到变量中(而不是将其读取到 $0 )。

以下示例仅打印奇数行。

$ awk -F"," '{getline tmp; print $0;}' items.txt
101,HD Camcorder,Video,210,10
103,MP3 Player,Audio,270,15
105,Laser Printer,Office,475,5

下面是它的工作原理:

  • 在主体块的开头,在执行任何语句之前,awk 读取 「items.txt」 的第一行并将其存储在 $0
  • getline tmp - 我们强制 awk 从输入文件中读取下一行并将其存储在 tmp 变量中。
  • print $0 - $0 仍然包含第一行,因为 "getline tmp" 没有覆盖 $0 的值。因此, print $0 将打印第一行(而不是第二行)。
  • 主体块以相同的方式继续处理 「items.txt」 中的其余行,并且仅打印奇数行。

以下示例同时打印 $0 tmp 。 如下所示, $0 包含奇数行, tmp 包含偶数行。

$ awk -F"," '{getline tmp; print "$0->", $0; print "tmp->", tmp;}' items.txt
$0-> 101,HD Camcorder,Video,210,10
tmp-> 102,Refrigerator,Appliance,850,2
$0-> 103,MP3 Player,Audio,270,15
tmp-> 104,Tennis Racket,Sports,190,20
$0-> 105,Laser Printer,Office,475,5
tmp-> 104,Tennis Racket,Sports,190,20

前面的两个示例从给定的输入文件本身读取该行。使用 getline 您还可以从不同的文件(与当前输入文件)读取行,如下所示。

在两个文件之间来回切换,打印每个文件中的行。

$ awk -F"," '{print $0; getline < "items-sold.txt"; print $0;}' items.txt
101,HD Camcorder,Video,210,10
101 2 10 5 8 10 12
102,Refrigerator,Appliance,850,2
102 0 1 4 3 0 2
103,MP3 Player,Audio,270,15
103 10 6 11 20 5 13
104,Tennis Racket,Sports,190,20
104 2 3 4 0 6 5
105,Laser Printer,Office,475,5
105 10 2 5 7 12 6 

下面是它的工作原理:

  • 在主体块的开头,在执行任何语句之前,awk 读取 「items.txt」 的第一行并将其存储在 $0
  • print $0 - 打印 「items.txt」 中的第一行
  • getline < "items-sold.txt" - 从 「itemssold.txt」 读取第一行并将其存储在 $0 中。
  • print $0 - 打印 「items-sold.txt」 中的第一行(不是 「items.txt」 中的)
  • 正文块以相同的方式继续 「items.txt」 和 「items-sold.txt」 中的其余行

您还可以使用 "getline var" 格式将不同文件中的行读入变量,而不是将这两个文件读入 $0

在两个文件之间来回切换,打印每个文件中的行(使用 tmp 变量)。

$ awk -F"," '{print $0; getline tmp < "items-sold.txt";print tmp;}' items.txt
101,HD Camcorder,Video,210,10
101 2 10 5 8 10 12
102,Refrigerator,Appliance,850,2
102 0 1 4 3 0 2
103,MP3 Player,Audio,270,15
103 10 6 11 20 5 13
104,Tennis Racket,Sports,190,20
104 2 3 4 0 6 5
105,Laser Printer,Office,475,5
105 10 2 5 7 12 6 

这与前面的示例相同,只是它将第二个文件中的行存储在变量 tmp 中。

您还可以使用 getline 执行 UNIX 命令并获取其输出。

以下示例获取 date 命令的输出并打印它。 请注意,您还应该关闭刚刚执行的命令,如下所示。date 命令的输出存储在 $0 变量中。

使用此方法可以在报告的页眉或页脚上打印时间戳。

$ cat getline1.awk
BEGIN {
    FS=",";
    "date" | getline
    close("date")
    print "Timestamp:" $0
}
{
    if ( $5 <= 5 )
        print "Buy More: Order", $2, "immediately!"
    else
        print "Sell More: Give discount on", $2, "immediately!"
}

$ awk -f getline1.awk items.txt
Timestamp:Sat Mar 5 09:29:22 PST 2011
Sell More: Give discount on HD Camcorder immediately!
Buy More: Order Refrigerator immediately!
Sell More: Give discount on MP3 Player immediately!
Sell More: Give discount on Tennis Racket immediately!
Buy More: Order Laser Printer immediately! 

您还可以将输出存储在任何 awk 变量(例如: timestamp )中,而不是将输出存储在 $0 变量中,如下所示。

$ cat getline2.awk
BEGIN {
    FS=",";
    "date" | getline timestamp
    close("date")
    print "Timestamp:" timestamp
}
{
    if ( $5 <= 5 )
        print "Buy More: Order", $2, "immediately!"
    else
        print "Sell More: Give discount on", $2, "immediately!"
}

$ awk -f getline2.awk items.txt
Timestamp:Sat Mar 5 09:38:22 PST 2011
Sell More: Give discount on HD Camcorder immediately!
Buy More: Order Refrigerator immediately!
Sell More: Give discount on MP3 Player immediately!
Sell More: Give discount on Tennis Racket immediately!
Buy More: Order Laser Printer immediately!