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

Chr*_*ris 4 bash awk

为什么这样做

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

和产出

No error
err ->BIST Login Fail 3922 err 
No error
err ->IR Remote Key 1 3310 err 
Run Code Online (Sandbox Code Playgroud)

但事实并非如此

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

和产出

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

我错过了什么?

Dav*_* W. 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
Run Code Online (Sandbox Code Playgroud)

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

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

find . -name "R*VER" -mtime +1 | while read myfile
do
   ...
done
Run Code Online (Sandbox Code Playgroud)

而不是这个:

for myfile in `find . -name "R*VER" -mtime +1`
do
   ...
done
Run Code Online (Sandbox Code Playgroud)

这有几个原因:

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

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


附录

现在我看到了正确意见的答案,我意识到你做错了什么:你忘记了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
Run Code Online (Sandbox Code Playgroud)

现在,问题是你到底在做什么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
Run Code Online (Sandbox Code Playgroud)

这样,你打印出来$SHELLVAR,但只有$SHELLVAR是空的.

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

find . -name "R*VER" -mtime +1 | while read myfile
do
   awk '/^err/ {print $0}' $myfile
done
Run Code Online (Sandbox Code Playgroud)


JUS*_*ION 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
Run Code Online (Sandbox Code Playgroud)

这样您就不必担心grep,不必担心shell变量,并且可以将逻辑全部保存在一种语言中.

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

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