有没有办法将变量从awk语句传递给bash函数作为参数?

时间:2014-07-21 20:05:13

标签: linux bash shell awk sed

我正在尝试使用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

4 个答案:

答案 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跳过前两行
  • 第一个while循环序列化表值而忽略第一列
  • 第二个while循环检查每个值并决定调用哪个函数
  • 两个while循环一起粗略地执行你的awk脚本所做的事。

答案 1 :(得分:2)

您无法直接从awk脚本调用shell函数。您的选择是:

  1. 将每个函数保存在单独的脚本文件中,并从awk或
  2. 调用该脚本
  3. 让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" 0470x27的八进制表示,'
  • 的ASCII / Unicode代码点
  • system()调用的命令直接写入stdout和stderr,只返回退出代码。如果要捕获awk中的输出,请输入| getline
  • 对于实际使用,应该使传递给shell函数的参数更加健壮(例如,如果值嵌入了双引号,则调用会中断;转义嵌入式双引号和嵌入式$实例(除非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