将shell参数传递给awk不起作用

时间:2011-06-16 22:47:48

标签: bash awk

为什么这样做

for myfile in `find . -name "R*VER" -mtime +1`
do
   SHELLVAR=`grep ^err $myfile || echo "No error"`
   ECHO $SHELLVAR
done

和输出

No error
err ->BIST Login Fail 3922 err 
No error
err ->IR Remote Key 1 3310 err 

但这不是

for myfile in `find . -name "R*VER" -mtime +1`
do
   SHELLVAR=`grep ^err $myfile || echo "No error"`
   awk -v awkvar=${SHELLVAR} '{print awkvar}'
done

和输出

awk: cmd. line:1: fatal: cannot open file `{print awkvar}' for reading (No such file or directory)

我错过了什么?

4 个答案:

答案 0 :(得分:5)

$SHELLVAR是否包含空格?如果是这样,你的awk脚本会被误解,并且{print awkvar}被假定为文件名而不是实际的AWK程序。

您还遇到一个问题, for 循环和 awk 程序都在啜饮STDIN。事实上,你的for循环只会被执行一次,因为AWK将在所有STDIN中读取,直到它完成。最后,你会一遍又一遍地获得同一行,然后你的程序将停止运行,因为awk等待更多STDIN。

我想你想做这样的事......

find . -name "R*VER" -mtime +1 | while read myfile
do
    echo "$SHELLVAR" | awk '{print $0}'
done

这样,你的echo命令会输入你的awk,这会阻止awk从find语句中读取。

顺便说一句,你最好这样做:

find . -name "R*VER" -mtime +1 | while read myfile
do
   ...
done

而不是:

for myfile in `find . -name "R*VER" -mtime +1`
do
   ...
done

这有几个原因:

  1. 命令行缓冲区可能会溢出,您将丢失文件名,但您永远不会看到错误。

  2. 第二个示例中的find命令必须先完成,然后才能开始执行for循环。在第一个示例中,查找提供到while循环。


  3. 附录

    现在我看到了just-my-correct-opinion的回答,我意识到你做错了什么:你忘记了awk命令中的文件名:

    find . -name "R*VER" -mtime +1 | while read myfile
    do
       SHELLVAR=`grep ^err $myfile || echo "No error"`
       awk -v awkvar=${SHELLVAR} '{print awkvar}' $myfile
    done
    

    现在,问题是你究竟在用awk做什么。除了$SHELVAR的值之外,您不会为文件中的每一行打印任何内容。这可能不是你想要做的。事实上,为什么不简单地这样做:

    find . -name "R*VER" -mtime +1 | while read myfile
    do
       SHELLVAR=$(grep -q "^err" $myfile")
       if [ "x$SHELLVAR" != "x" ]
       then
          echo "$SHELLVAR"
       fi
    done
    

    这样,您打印$SHELLVAR,但仅当$SHELLVAR为空。

    或者,您可以使用awk仅打印出与正则表达式匹配的行:

    find . -name "R*VER" -mtime +1 | while read myfile
    do
       awk '/^err/ {print $0}' $myfile
    done
    

答案 1 :(得分:5)

你想做的事情是可能的,但......有点古怪。这是您的另一种选择:

for f in $(find . -name "R*VER" -mtime +1)
do
    echo "$f"
    awk 'BEGIN{ec=0} /^err/{ec+=1;print} END{if(ec==0){print "No error"}}' "$f"
done

这样您就不必担心grep,不必担心shell变量,并且可以用一种语言将逻辑保存在一个地方。

请注意,此代码仅部分测试,因为我没有您的数据文件,但测试我做得很好。

如果你愿意,你甚至可以更进一步,在awk中写下整件事。毕竟,它是一种完整的通用编程语言(IMO,比bash更清晰的语法)。这样您就可以完全避免使用findgrepbash。但是,我不会写那个剧本。您必须选择awk手册页并自行阅读文件I / O.

答案 2 :(得分:4)

您需要引用$SHELLVAR,以防止shell分裂它。

awk -v awkvar="${SHELLVAR}" '{print awkvar}'

答案 3 :(得分:1)

您已经有了替代解决方案。无论如何,我只想回答你的问题,即你缺少的东西:

awk -v awkvar=${SHELLVAR} '{print awkvar}'

这里awk正在寻求从STDIN读取输入。这就是问题。 Awk试图从STDIN读取输入,除非您指定输入文件。对输入中的每个RECORD执行awk的给定命令(默认情况下,记录是一行)。请参阅man awk以了解有关awk的更多信息。

但是如果你想让它在没有任何输入的情况下继续进行,那么这是一个黑客攻击:

awk -v awkvar=${SHELLVAR} 'BEGIN{print awkvar}'

一旦调用awk,就会执行BEGIN块。如果awk找不到除BEGIN之外的任何其他块,则会执行这些BEGIN块并退出。

我希望你能解决错误背后的问题,并为此提供快速解决方案。