为什么双引号awk命令替换在csh中失败

时间:2018-08-19 14:28:42

标签: awk csh tcsh

使用C Shell,以下命令行

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

返回awk错误:

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

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

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

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

1 个答案:

答案 0 :(得分:0)

经过一番修补,我只能得出结论,它是那些C-Shell怪癖之一。 C壳(cshtcsh)显然以其peculiarities闻名,我相信这正是这里发生的事情。以下是一些基于OP的示例的示例。

未引用:

$ 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

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

$ 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但只能在双引号中!

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

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

词法结构

     

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

     

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

     

来源:\

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

man csh

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

$ 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

可以潜在地解决问题。