我正在尝试使用bash脚本中的awk
语句查找(例如1或4和2或3)文本文件中的某些特定值。如果在文件中找到此值(在awk
语句中),那么我想从awk
语句之外调用一个函数,并将找到的值作为参数传递给它。
我的问题:(1)这可能吗?如果是这样呢? (2)如果不可能或有更好的方法,那么如何?
请注意,我在搜索文件时正在跳过文本文件的前两行。如果需要进一步解释,请告诉我。
file.txt的
Name Col1 Col2 Col3
-----------------------
row1 1 4 7
row2 2 5 8
row3 3 6 9
实际函数retrieve
比这个简化示例复杂得多。所以我需要调用此函数,因为我不想将它放在awk
语句中。
编辑1:我正在使用GNU AWK
编辑2:如果找到2或3,我说我有另一个功能。它会如何运作?
function retrieve {
if [[ "$1" == "1" ]]; then
echo "one beer on the wall"
elif [[ "$1" == "4" ]]; then
echo "four beers on the wall"
fi
}
function retrieve2 {
if [[ "$1" == "2" ]]; then
echo "two beers on the wall"
elif [[ "$1" == "3" ]]; then
echo "three beers on the wall"
fi
}
awk -F '\t' '
FNR < 2 {next}
FNR == NR {
for (i=2; i <= NF; i++)
{
if (($i == 1) || ($i == 4))
printf(%s, "'retrieve "$i" '") # Here is the problem
if (($i == 2) || ($i == 2))
printf(%s, "'retrieve2 "$i" '") # Here is the problem
}
}
' file.txt
答案 0 :(得分:4)
跳过awk并在bash中执行所有操作
tail -n +3 file.txt | while read -r ignored c1 c2 c3; do
echo "$c1"
echo "$c2"
echo "$c3"
done | while read -r value; do
if [ "$value" -eq 1 -o "$value" -eq 4 ]; then
retrieve "$value"
elif [ "$value" -eq 2 -o "$value" -eq 3 ]; then
retrieve2 "$value"
fi
done
解释
tail
跳过前两行答案 1 :(得分:2)
您无法直接从awk脚本调用shell函数。您的选择是:
答案 2 :(得分:2)
虽然一般来说这不是一个好主意,但首先出于性能原因,从awk调用bash
函数是一种麻烦的方法。
基本方法是导出感兴趣的功能,然后通过bash -c 'funcName arg ...'
中的awk
调用它们。
这是一个概念证明:
# DEFINE the function to be called from awk.
# The function simply prints its arguments one by one in diagnostic fashion.
retrieve() { local a i=0; for a; do echo "\$$((i+=1))=[$a]"; done; }
# EXPORT it, so that bash instances created by awk see the function.
export -f retrieve
# Simple awk program that demonstrates calling retrieve()
# with an argument.
awk -v q=\' 'BEGIN {
# Define some value to pass to the shell function.
argToPass="some value"
# Construct the command line that will call the shell function.
# Note that since a *function* is being invoked, the arguments
# must be passed as part of single string passed to -c.
ec=system("bash -c " q "retrieve \"" argToPass "\"" q)
# Print the exit code.
print ec
}'
请注意,每次调用shell函数都会创建 2 子进程,因为awk函数system()
总是调用sh
(可能是也可能不是bash
在你的系统上),在这种情况下反过来显式调用bash
。
-v q=\'
只是一个辅助变量,可以更容易地在awk程序中使用单引号构造字符串。另外,正如@EdMorton指出的那样,您可以将\047
转义序列直接嵌入到awk字符串文字中:"bash -c \047retrieve \"" argToPass "\"\047"
。 047
是0x27
的八进制表示,'
system()
调用的命令直接写入stdout和stderr,只返回退出代码。如果要捕获awk中的输出,请输入| getline
。$
实例(除非shell扩展是需要)。答案 3 :(得分:1)
请不要接受这个答案 - 它只是继续(并希望帮助)Ed的回答和你的进一步问题。
是的,您可以将awk
的输出存储在bash数组中,如下所示:
array=( $(awk 'BEGIN{print 1,2,3}') )
echo ${array[0]}
1
echo ${array[1]}
2
echo ${array[2]}
3