我正在尝试了解bash和awk中的具体情况:
我想使用awk 二元运算符将两个变量之间的字符串连接(空格)作为变量迭代$i
,在bash中循环:
$ for i in ' '; do
echo "foo bar" | awk '{print $1$i$2}'
done
foofoo barbar
预期输出为:foobar
$ $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
答案 0 :(得分:4)
这似乎有点棘手。实际上它会打印foo
,foo bar
和bar
。由于i
中没有定义$0
的值(它是awk变量),因此它被视为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