为什么双引号awk命令替换在csh中失败 [英] why is a double-quoted awk command substitution failing in csh

查看:286
本文介绍了为什么双引号awk命令替换在csh中失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用C Shell,以下命令行

Using C shell, the following command-line

set pf = "`awk -v var=$pd '{if($1<0) print var, $2, $3}' test.txt`"

返回awk错误:

awk: {if( <0) print var, , } syntax error. 

这特别令人困惑,因为命令本身可以正常工作:

This is especially puzzling as the command itself works without any problem:

awk -v var=$pd '{if($1<0) print var, $2, $3}' test.txt

有没有一种方法可以将单个Awk命令行的所有输出存储到单个变量中?以上失败的原因是什么?

Is there a way that we can store all output of the single Awk command line into a single variable? What is the reason the above is failing?

推荐答案

经过一番修补,我只能得出结论,它是那些C-Shell怪癖之一. C-shell(cshtcsh)显然以其

After some tinkering, I can only come to the conclusion that it is one of those C-Shell quirks. C-shell (csh or tcsh) is apparently notoriously known for its peculiarities, and I believe that this is exactly what is going on here. Here are some examples, based on the OP's enigma.

未引用:

$ set a = `echo a_b c | awk '{print $1}'` ; echo $a
a_b
$ set a = `echo a_b c | awk '{print $1,2}'` ; echo $a
a_b 2
$ set a = `echo a_b c | awk '{print $1 OFS 2}'` ; echo $a
a_b 2

引用:

$ set a = "`echo a_b c | awk '{print $1}'`" ; echo $a
a_b c
$ set a = "`echo a_b c | awk '{print $1,2}'`" ; echo $a
awk: cmd. line:1: {print ,2}
awk: cmd. line:1:        ^ syntax error
$ set a = "`echo a_b c | awk '{print $1 OFS 2}'`" ; echo $a
2

因此,在带双引号的示例中,看起来$1替换为空字符串.这解释了为什么第一种情况打印全行a_b c,而第三种情况仅打印数字2.第二个失败,因为Awk语句print ,2是无效的,而第一个以print的形式等效于Awk中的print $0.

So, in the double-quoted examples, it looks like $1 is replaced by an empty string. This explains why the first case prints the full line a_b c and the third just the number 2. The second fails as the Awk statement print ,2 is invalid while the first works as print is equivalent to print $0 in Awk.

如果您玩的更多,您实际上会注意到C-shell尝试进行变量替换.实际上,您不需要在所有上述内容中使用set,只需简单的双引号命令替换即可.下面的示例完全显示了香蕉的样子:

If you play a bit more, you actually notice that C-shell tries to do variable substitution. You actually do not need to use set in all the above, just a simple double-quoted command substitution. The following example shows completely how bananas this is:

$ echo $0
csh
$ echo "`echo a_b c | awk '{print $0}'`"

$ echo "`echo a_b c | awk -v csh=foo '{print $0}'`"
foo
$ echo `echo a_b c | awk -v csh=foo '{print $0}'`
a_b c

因此,您会看到C-Shell正在执行变量替换,并且$0被替换为字符串csh. 但只能在双引号中!

So from this, you see that C-Shell is performing the variable substitutions and $0 is being replaced with the string csh. But only in the double-quoted version!

那么,为什么会这样?原因是双引号.双引号字符串允许变量替换,而不必考虑双引号字符串中嵌套引号的用法.因此,即使Awk行在向后引用的字符串中被单引号引起来,双引号仍将对$n进行变量替换.这与Bash相反:

So, why is this the case? The reason is the double-quotes. A double-quoted string allows variable substitution, disregarding the usage of nested quotes within the double-quoted string. So, even though, the Awk line is single-quoted in a back-wards quoted string, the double-quotes still will do the variable substitution on $n. This is in contrast to Bash:

$ echo $0
bash
$ echo "`echo a_b c | awk -v csh=foo '{print $0}'`"
a_b c

词法结构

此外,除历史记录替换外,所有替换(请参见下文)都可以通过用单引号引起来的字符串(或部分字符串)用单引号引起来或通过引用关键字符来防止(例如,分别为$`分别用于变量替换或命令替换)与\. (别名替换也不例外:以任何方式引用已定义别名的单词的任何字符都可以防止替换 别名.引用别名的常用方法是在其前面加上反斜杠.)历史记录替换由反斜杠而不是单引号引起来. 用双引号或反引号引起来的字符串会进行变量替换和命令替换,但是会禁止其他替换.

Furthermore, all Substitutions (see below) except History substitution can be prevented by enclosing the strings (or parts of strings) in which they appear with single quotes or by quoting the crucial character(s) (e.g., $ or ` for Variable substitution or Command substitution respectively) with \. (Alias substitution is no exception: quoting in any way any character of a word for which an alias has been defined prevents substitution of the alias. The usual way of quoting an alias is to precede it with a backslash.) History substitution is prevented by backslashes but not by single quotes. Strings quoted with double or backward quotes undergo Variable substitution and Command substitution, but other substitutions are prevented.

引用复杂的字符串,尤其是本身包含引号的字符串可能会造成混淆.请记住,在人类写作中不必使用引号!并非只引用整个字符串,而是只引用需要引用的字符串部分,如果需要的话,可以使用不同类型的引用来引用.

Quoting complex strings, particularly strings which themselves contain quoting characters, can be confusing. Remember that quotes need not be used as they are in human writing! It may be easier to quote not an entire string, but only those parts of the string which need quoting, using different types of quoting to do so if appropriate.

来源:man csh

那么,如何解决呢?尽管C-shell完全不直观并且在心理上是引用的噩梦,但可以通过提前终止引用并将其从double更改为double来解决问题.在短时间内用单引号引起来.

So, how can this be solved? While C-shell is completely non-intuitive and mentally a quoting nightmare, it is possible to fix the problem by terminating the quoting early and change from double to single-quotes for a short time.

$ echo "`echo a_b c | awk -v csh=foo '{print "'$0,$1'"}'`"
a_b c a_b
$ echo "`echo a_b c | awk -v csh=foo '"'{print $0,$1}'"'`"
a_b c a_b

解决方案:因此,在完成所有这些之后,我认为我们可以得出结论

Solution: So after all this, I think we can conclude that

$ set pf = "`awk -v var=$pd '"'{if($1<0) print var, $2, $3}'"' test.txt`"

可以潜在地解决问题.

这篇关于为什么双引号awk命令替换在csh中失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆