在 awk 打印中使用 bash for 循环变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35811546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 14:20:41  来源:igfitidea点击:

Using bash for loop variable within awk print

bashawk

提问by adam

I'm trying to understand a specific situation within bash and awk:

我试图了解 bash 和 awk 中的特定情况:

I want to use the awk binary operatorfor string concatenation between two variables(a space) as the variable iterated,$i, within a bash for loop:

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

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

Expected output is: foobar

预期输出为: foobar

Question 1

问题 1

  • What is going on? ANSWER(marked as correct)
  • 到底是怎么回事?答案(标记为正确)

Question 2

问题2

  • How can I get awk to use string concatenation as in the above bash for loop? ANSWER
  • 我怎样才能让 awk 像上面的 bash for 循环一样使用字符串连接?回答

Reference

参考

$ $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)

Full test

全面测试

$ for i in '+' '-' '*' '/' '%' ' ' ''; do echo "2.0 4.0" | awk '{print $i}'; 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

回答by TrueY

It seems to be a little bit tricky one. Actually it prints foo, foo barand bar. As the value of iis not defined in awk(it is a bashvariable) it is considered as $0(I did not know this behavior, but it make sense).

这似乎有点棘手。实际上它打印foo,foo barbar。由于awk 中i没有定义的值(它是一个bash变量),它被认为是(我不知道这种行为,但它是有道理的)。$0

Change the code a little bit as

将代码稍微更改为

for i in ' '; do 
  echo "foo bar" | awk '{print "<"$i">"}'
done

Output:

输出:

foo<foo bar>bar

If you want to pass the value of the variable iyou can do using -vargument. But $iwill not work as the value of ishould be a number in $i, so just use simple i.

如果你想传递变量的值,i你可以使用-v参数。但是$i不会因为 的值i应该是一个数字而工作$i,所以只需使用 simple i

for i in ' '; do
  echo "foo bar" | awk -v i="$i" '{print "<"i">"}'
done

Output:

输出:

foo< >bar

回答by Ed Morton

I tried making this a comment but there's just too much to say and some of it needs formatting:

我尝试将此作为评论,但要说的太多了,其中一些需要格式化:

@adam you seem to have some fundamental misunderstanding of awk that's making it hard for you to grasp what you're being told. I suspect it comes down to this - awk is not shell. Awk is a completely separate tool/language with it's own scope, variables, functions, etc.

@adam 你似乎对 awk 有一些根本性的误解,这让你很难理解别人告诉你的内容。我怀疑这归结为 - awk 不是 shell。awk 是一种完全独立的工具/语言,具有自己的作用域、变量、函数等。

Do NOT try to access the value of shell variables directly within an awk script by using intermediate single quotes (e.g. awk '{print $1'"$i"'$2}') because that will turn the value of the shell variable into part of the awk code before the interpreter reads it and open you up to horrendous errors with cryptic error messages (or worse - insidious bugs with no error messages) given various values of $i.

不要试图通过使用中间单引号(如直接在awk脚本访问shell变量的值awk '{print $1'"$i"'$2}'),因为这将会把shell变量的值改成awk的部分代码解释读取它之前打开你到可怕给定各种值的$i.

You say you Cannot get -v to work even without for loop:but then you show it working perfectly twice:

你说你Cannot get -v to work even without for loop:,然后你证明它完美地工作了两次:

$ echo "foo bar" | awk -v var=" " '{print var}'
foo bar

In the above case you create an awk variable named varthat contains one blank character " ". Then you print $1 (foo) followed by var (" ") followed by $2 (bar) and the output is <foo>< ><bar>exactly as it should be.

在上述情况下,您创建了一个名为 awk 的变量var,其中包含一个空白字符" "。然后打印 $1 ( foo) 后跟 var ( " ") 后跟 $2 ( bar) ,输出<foo>< ><bar>完全符合它应有的样子。

In all of your examples you are setting a variable to a single space character, concatenating that with some other values (e.g. -v var=" "then $1var$2) and then for some reason expecting that space character to not be present in the output.

在您的所有示例中,您都将变量设置为单个空格字符,将其与其他一些值(例如-v var=" "then $1var$2)连接起来,然后由于某种原因期望该空格字符不会出现在输出中。

$ echo "foo bar" | awk -v var=" " '{print 'var'}'
foo bar

In the above case you create an awk variable named varthat contains one blank character " ". When you write any shell script (awk, sed, grep, whatever) that's enclosed in single quotes:

在上述情况下,您创建了一个名为 awk 的变量var,其中包含一个空白字符" "。当您编写任何用单引号括起来的 shell 脚本(awk、sed、grep 等)时:

any_cmd 'abc'

then you are telling cmdto interpret/execute what's inside the sign quotes. You cannotinclude single quotes in a single quote delimited script - that's shell fundamentals. So when you write:

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

any_cmd 'abc'def'ghi'

the inner single quotes are actually breaking out of the any_cmdlanguage and back to shell to interpret and the shell attempts to it expand it before any_cmdis called. So if you have:

内部单引号实际上是脱离any_cmd语言并返回到 shell 进行解释,shell 尝试在any_cmd调用之前对其进行扩展。所以如果你有:

xyz=17
any_cmd 'abc'$xyz'ghi'

then what any_cmdactually sees to interpret is:

那么any_cmd实际看到的解释是:

any_cmd 'abc17ghi'

but if you have something in there that the shell can't expand then it gets left as-is so:

但是如果你有一些东西,shell 无法扩展,那么它就会保持原样:

and_cmd 'abc'def'ghi'

gets passed to any_cmdas:

被传递给any_cmd

any_cmd 'abcdefghi'

So back to your example:

所以回到你的例子:

$ echo "foo bar" | awk -v var=" " '{print 'var'}'
foo bar

The varbetween $1 and $2 will be interpreted by the shell first since the 's around it are taking it out of the awk script and back to shell, but then it's just some text that shell can't expand so the above is passed to awk as-is which makes it:

var之间$ 1和$ 2将被shell解释第一,因为'它周围s的取出来的awk脚本和背壳,但那么它只是一些文字,外壳无法展开,因此上述传递给AWK为-是这使得它:

$ echo "foo bar" | awk -v var=" " '{print var}'

and in a roundabout way you got back to your first script and again the output is as expected.

并以一种迂回的方式返回到您的第一个脚本,并且输出再次符合预期。

The above sounds complicated but it's actually extremely simple:

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

To concatenate strings in awk, just put them side by side.

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

To pass the value of a shell variable to awk, use -v, e.g. awk -v awkvar="$shellvar" 'print "foo" awkvar "bar"'.

要将 shell 变量的值传递给 awk,请使用-v,例如awk -v awkvar="$shellvar" 'print "foo" awkvar "bar"'

Rather than trying to learn awk by trial and error, read the book Effective Awk Programming, 4th Edition, by Arnold Robbins first and then play with it.

与其尝试通过反复试验来学习 awk,不如先阅读 Arnold Robbins 所著的 Effective Awk Programming,第 4 版,然后再使用它。

回答by adam

Ah, I figured out Question 2.

啊,我想通了问题2

Initial for loop:

初始 for 循环:

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

Explore: quoting

探索:引用

Enclose $iin ":
'{print $1$i$2}'to
'{print $1"$i"$2}'

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

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

Solution: quoting

解决方案:引用

Which led me to trying to break up awk with 'so $ican be correctly evaluated:
'{print $1"$i"$2}'to
'{print $1'"$i"'$2}'

这使我想分手AWK用'这样$i可以正确评估:
'{print $1"$i"$2}'
'{print $1'"$i"'$2}'

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

Test solution

测试解决方案

Using solution to test all awk binary operators and null:

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

$ for i in '+' '-' '*' '/' '%' ' ' ''; do 
    echo "2.0 4.0" | awk '{print "Using binary operator \"'"$i"'\" for \"""\" and \"""\" evaluates to:\t" '"$i"'}'; 
  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

Note: ''is not a binary operator obviously and is just a check.

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

Success!

成功!

Warning: as pointed out by others, this solution is not for general string concatenation. The shell variable ishould only be awk binary operators. Setting ito any other variable will probably cause issues.

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

Explore: -v

探索: -v

Using -vdoes not appear to allow binary operation:

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

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

Output: 2.0+4.0
Desired output: 6

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