Wil*_*ard 3 performance scripting bash awk
这有点棘手;我正在尝试找出解决此问题的最佳方法。我有几种方法,但它们看起来很笨拙,我想要更优雅的东西。
我想解析一个空格分隔的文件,忽略#comment lines并抱怨任何不具有 4 个字段的非空行。这在以下方面很容易awk:
awk '/^#/ {next}; NF == 0 {next}; NF != 4 {exit 1}; (dostuff)'
Run Code Online (Sandbox Code Playgroud)
诀窍是我想对数据做些什么,实际上是将其设置为变量bash,然后运行一个bash函数,除非 $2 包含特定值。
这是一些伪代码(主要是真实但混合语言)来解释我的意思:
# awk
/^#/ {next}
NF == 0 {next}
NF != 4 {exit 1}
$2 == "manual" {next}
# bash
NAME=$1
METHOD=$2
URL=$3
TAG=$4
complicated_bash_function_that_calls_lots_of_external_commands
# then magically parse the next line with awk.
Run Code Online (Sandbox Code Playgroud)
我不知道如何在没有一些丑陋的解决方法的情况下执行此操作,例如调用awk或sed单独调用文件的每一行。(最初我提出的问题是“如何从 awk 中调用 bash 函数或从 bash 中调用 awk 的每个输出行?”)
可能将 bash 函数修改为它自己的脚本,并使其接受上述参数 1、2、3、4。不过,我不确定如何从 awk 中调用它;因此我的问题标题。
我实际上更喜欢做的是将整个文件放在一个文件中,并使其成为 bash 脚本 -awk从内部调用bash而不是bash从awk. 但是我仍然需要从 awk 中调用该bash 函数——对输入文件的每个非注释行调用一次。
我怎样才能做到这一点?
您可以通过管道awk的输出到while read循环中来做您想做的事情。例如:
awk '/^#/ {next}; NF == 0 {next}; NF != 4 {exit 1} ; {print}' |
while read -r NAME METHOD URL TAG ; do
: # do stuff with $NAME, $METHOD, $URL, $TAG
echo "$NAME:$METHOD:$URL:$TAG"
done
if [ "$PIPESTATUS" -eq 1 ] ; then
: # do something to handle awk's exit code
fi
Run Code Online (Sandbox Code Playgroud)
测试:
$ cat input.txt
# comment
NAME METHOD URL TAG
a b c d
1 2 3 4
x y z
a b c d
$ ./testawk.sh input.txt
NAME:METHOD:URL:TAG
a:b:c:d
1:2:3:4
Run Code Online (Sandbox Code Playgroud)
请注意,它在第五个x y z输入行正确退出。
值得指出的是,由于while循环是管道的目标,它在子 shell 中执行,因此无法更改其父脚本的环境(包括环境变量)。
如果需要,则不要使用管道,而是使用重定向和进程替换:
$ cat input.txt
# comment
NAME METHOD URL TAG
a b c d
1 2 3 4
x y z
a b c d
$ ./testawk.sh input.txt
NAME:METHOD:URL:TAG
a:b:c:d
1:2:3:4
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用coproc内置程序在后台运行 awk 脚本作为协同进程:
while read -r NAME METHOD URL TAG ; do
: # do stuff with $NAME, $METHOD, $URL, $TAG
echo "$NAME:$METHOD:$URL:$TAG"
done < <(awk '(/^#/ || NF == 0) {next};
NF != 4 {
printf "%s:%s:Wrong number of fields\n", FILENAME, NR > "/dev/stderr";
exit 1
};
{print}' input.txt)
# getting the exit code from the <(...) requires bash 4.4 or newer:
wait $!
if [ "$?" -ne 0 ] ; then
: # something went wrong in the process substitution, deal with it
fi
Run Code Online (Sandbox Code Playgroud)