从 awk 获取边值的更好方法

从 awk 获取边值的更好方法

我有一个脚本,其主要目的是收集一些信息并将其输出到表中。主要部分是 awk 脚本:

awk '
    { 
      # do some stuff, including calculating dwt
      printf(format, a, b, c, d)
    }
    END {
      # pass on dwt
    }
' inputfile

awk 的主要目的是创建和显示表。但是它还计算出我在主脚本中其他地方需要的一个侧面值dwt,并且我正在尝试找出在不中断表输出的情况下传递它的最佳方法。

我知道有两种方法可以做到这一点:

  1. 将值保存到临时文件:END { print dwt > "tempfile" }然后在外部读取它read dwt <tempfile; rm -f tempfile。但即使比这里显示的更小心地避免破坏现有文件,我还是更愿意避免这种情况 - 如果没有别的办法,我不想仅仅因为作业在错误的时间被中断而将临时文件留在周围。
  2. 也将值发送到标准输出,但已标记。将 stdout 通过管道传输到以下例程中,该例程捕获并适当地引导标记的输出,但发送其余部分:
    awk '
       ...
        END { 
           print "dwt:" dwt 
        }
     ' inputfile | while read line; do
        if [[ $line = dwt:* ]]; then
           dwt="${line#dwt:}"
        else
           echo "$line"
        fi
     done

但这似乎做作且不优雅。

我想知道是否有人知道更好的方法。我尝试过使用不同的文件描述符,但到目前为止还没有成功。我还没有弄清楚如何在不破坏标准输出的情况下从文件描述符中获取信息并放入 dwt 环境变量中。

答案1

这是一种技术:

  • 在 END 的 stdout 上打印 dwt
  • 将 awk 输出捕获到数组中
  • 将数组的最后一个元素提取到 shell 进程中的变量中
  • 打印数组的其余部分
$ seq 5 > inputfile
$ readarray -t output < <(
    awk '
        { print "table", $0; dwt += $1 }
        END {print dwt}
    ' inputfile
)
$ dwt=${output[-1]}
$ echo "dwt = $dwt"
dwt = 15
$ unset output[-1]
$ printf "%s\n" "${output[@]}"
table 1
table 2
table 3
table 4
table 5

好的,ksh 不带readarray: 您的 shell 脚本可能如下所示:

awk '
    { 
      # do some stuff, including calculating dwt
      printf(format, a, b, c, d)
    }
    END {
      # pass on dwt
      print dwt
    }
' inputfile  |&
# ...........^^

typeset -a output
while IFS= read -r -p line; do output+=( "$line" ); done
# .................^^

dwt=${output[-1]}
unset output[-1]
printf "%s\n" "${output[@]}"

# do stuff with $dwt ...

从我的 ksh93 手册页:

该符号|&导致前面的管道异步执行,并与父 shell 建立了双向管道;生成的管道的标准输入和输出可以通过使用-p 内置命令的选项由父 shell 写入和读取, read稍后print将对此进行描述。

答案2

有点笨拙,但你可以在awk评估中打印 shell 命令ksh

eval $( echo -e 1\\nA\\n2\\n3\\n4 |
  awk  'NR == 1 {printf"%s%s%s;","export var1=",$0, "\n"}
        NR > 2 {printf"%s%s%s;","echo -e '", $0 , "'\n" }'
)

输出:

2
3
4

$ echo $var1
1

尽管逐行 shell 评估可能不是最简单的,并且在某些字符串的情况下,回显可能会给出有趣的结果。请注意这种危险!,但硬引用应该避免这种情况:

eval $( echo -e 1\\nA\\n2\\n3\\n4 |
  awk  'NR == 1 {printf"%s%s%s;","export var1=",$0, "\n"}
        NR > 2 {printf"%s%s%s;","echo -e \x27", $0 , "\x27\n" }'
)

相关内容