在awk print中使用bash for loop变量

时间:2016-03-05 07:47:08

标签: bash awk

我正在尝试了解bash和awk中的具体情况:

我想使用awk 二元运算符两个变量之间的字符串连接(空格)作为变量迭代$i,在bash中循环:

$ for i in ' '; do 
  echo "foo bar" | awk '{print $1$i$2}'
done
foofoo barbar

预期输出为:foobar

问题1

  • 发生了什么事? ANSWER(标记为正确)

问题2

  • 如何在上面的bash for循环中使用awk来使用字符串连接? ANSWER

参考

$ $SHELL --version | head -n1
GNU bash, version 4.3.42(4)-release (x86_64-unknown-cygwin)

$ awk --version | head -n1
GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.3, GNU MP 6.1.0)

完整测试

$ for i in '+' '-' '*' '/' '%' ' ' ''; do echo "2.0 4.0" | awk '{print $1$i$2}'; done
2.02.0 4.04.0
2.02.0 4.04.0
2.02.0 4.04.0
2.02.0 4.04.0
2.02.0 4.04.0
2.02.0 4.04.0
2.02.0 4.04.0

3 个答案:

答案 0 :(得分:4)

这似乎有点棘手。实际上它会打印foofoo barbar。由于i中没有定义$0的值(它是变量),因此它被视为for i in ' '; do echo "foo bar" | awk '{print $1"<"$i">"$2}' done (我不知道这种行为,但它有意义)。

将代码更改为

foo<foo bar>bar

输出:

i

如果要传递变量-v的值,可以使用$i参数。但i无效,因为$i的值应为i中的数字,因此只需使用简单的for i in ' '; do echo "foo bar" | awk -v i="$i" '{print $1"<"i">"$2}' done

foo< >bar

输出:

<?xml version="1.0" encoding="utf-8" ?>
 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
  <ResponseId xmlns="http://www.mhotel.com/"/>
  </soap:Header>
<soap:Body>
  <ns3:NotifRQ Status="yes" Token="ggggg" xmlns:ns2="http://www.yyyyyy.com/"     xmlns:ns3="http://www.ffffff.org/uuu/">
   </ns3:NotifRQ>

答案 1 :(得分:2)

我试过把它作为评论,但是说的太多了,有些需要格式化:

@adam你似乎对awk有一些根本的误解,这让你很难理解你被告知的内容。我怀疑它归结为此 - awk不是shell 。 Awk是一个完全独立的工具/语言,具有自己的范围,变量,函数等。

不要尝试使用中间单引号(例如awk '{print $1'"$i"'$2}')直接在awk脚本中访问shell变量的值,因为这会将shell变量的值转换为解释器之前的awk代码的一部分根据{{​​1}}的各种值,读取它并使用神秘的错误消息(或者更糟糕的是 - 没有错误消息的阴险错误)打开你的骇人听闻的错误。

你说你$i但是你表明它完美地工作了两次:

Cannot get -v to work even without for loop:

在上面的例子中,您创建了一个名为$ echo "foo bar" | awk -v var=" " '{print $1var$2}' foo bar 的awk变量,其中包含一个空白字符var。然后打印$ 1(" "),然后是var(foo),接着是$ 2(" "),输出为bar,与应有的完全相同。

在所有示例中,您要将变量设置为单个空格字符,将其与其他一些值连接(例如<foo>< ><bar>然后-v var=" "),然后由于某种原因预期空格字符不会出现在输出中。

$1var$2

在上面的例子中,您创建了一个名为$ echo "foo bar" | awk -v var=" " '{print $1'var'$2}' foo bar 的awk变量,其中包含一个空白字符var。当你编写任何用单引号括起来的shell脚本(awk,sed,grep等)时:

" "

然后你告诉any_cmd 'abc' 解释/执行符号引号内的内容。您不能在单引号分隔的脚本中包含单引号 - 这是shell的基础知识。所以当你写:

cmd

内部单引号实际上是从any_cmd 'abc'def'ghi' 语言中删除并返回到shell来解释,并且shell会在调用any_cmd之前尝试扩展它。所以如果你有:

any_cmd

然后xyz=17 any_cmd 'abc'$xyz'ghi' 实际看到的解释是:

any_cmd

但是如果你在那里有东西,那么shell无法展开,那么它就会保持原样:

any_cmd 'abc17ghi'

传递给and_cmd 'abc'def'ghi'

any_cmd

回到你的例子:

any_cmd 'abcdefghi'

$ 1和$ 2之间的$ echo "foo bar" | awk -v var=" " '{print $1'var'$2}' foo bar 将首先由shell解释,因为它周围的var将它从awk脚本中取出并返回shell,但是它只是一些文本shell无法扩展,因此将上面的内容传递给awk as-is,使其成为:

'

以迂回的方式回到你的第一个脚本,然后再次按预期输出。

以上听起来很复杂,但实际上非常简单:

要在awk中连接字符串,只需将它们并排放置即可。

要将shell变量的值传递给awk,请使用$ echo "foo bar" | awk -v var=" " '{print $1var$2}' ,例如-v

不要试图通过反复试验来学习awk,而是首先阅读Arnold Robbins的“Effective Awk Programming,4th Edition”一书,然后再玩它。

答案 2 :(得分:0)

啊,我想出了问题2

循环初始化:

$ for i in ' '; do echo "foo bar" | awk '{print $1$i$2}'; done
foofoo barbar

探索:引用

$i加入"
'{print $1$i$2}'
'{print $1"$i"$2}'

$ for i in ' '; do echo "foo bar" | awk '{print $1"$i"$2}'; done
foo$ibar

解决方案:引用

这导致我尝试使用'来解析awk,因此可以正确评估$i
'{print $1"$i"$2}'
'{print $1'"$i"'$2}'

$ for i in ' '; do echo "foo bar" | awk '{print $1'"$i"'$2}'; done
foobar

测试解决方案

使用解决方案测试所有awk二元运算符并返回null:

$ for i in '+' '-' '*' '/' '%' ' ' ''; do 
    echo "2.0 4.0" | awk '{print "Using binary operator \"'"$i"'\" for \""$1"\" and \""$2"\" evaluates to:\t" $1'"$i"'$2}'; 
  done
Using binary operator "+" for "2.0" and "4.0" evaluates to:     6
Using binary operator "-" for "2.0" and "4.0" evaluates to:     -2
Using binary operator "*" for "2.0" and "4.0" evaluates to:     8
Using binary operator "/" for "2.0" and "4.0" evaluates to:     0.5
Using binary operator "%" for "2.0" and "4.0" evaluates to:     2
Using binary operator " " for "2.0" and "4.0" evaluates to:     2.04.0
Using binary operator "" for "2.0" and "4.0" evaluates to:      2.04.0

注意:''显然不是二元运算符,只是一个检查。

成功!

警告:正如其他人所指出的,此解决方案不适用于一般字符串连接。 shell变量i应该只是awk二元运算符。将i设置为任何其他变量可能会导致问题。

探索:-v

使用-v似乎不允许二进制操作:

$ echo "2.0 4.0" | awk -v var="+" '{print $1var$2}'
2.0+4.0

输出:2.0+4.0
期望的输出:6