Unix'别名'失败了'awk'命令

时间:2014-06-16 14:10:17

标签: linux shell awk

我在Unix中创建别名并发现以下命令失败..

alias logspace='find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | awk '{print $5, $9 }''

我得到以下内容:

awk: cmd. line:1: {print
awk: cmd. line:1:       ^ unexpected newline or end of string

关于为什么管道awk命令失败的任何想法......

谢谢, 肖恩。

4 个答案:

答案 0 :(得分:39)

补充@Dropout's helpful answer

TL;博士

问题在于OP尝试在{/ 1}} ' - 附带(单引号)字符串中使用'

在这种情况下,最强大的解决方案是'替换每个内部 '\'' (原文如此) :

alias logspace='find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | 
                awk '\''{print $5, $9 }'\'''
  • Bourne-like(POSIX兼容)shell不支持在单引号(' - 封闭的)字符串中使用'...'个字符串 - 甚至不用转义
    • (相比之下,您可以在引用的字符串中将"转义为\",并且,如@ Droput的答案,您可以直接,嵌入'字符,但请看下面的陷阱。)
  • 上面的解决方案有效地从多个单引号字符串构建字符串,文字'字符。 - 转义单引号字符串\' - 拼接在
    另一种表达方式,正如@Etan Reisinger在评论中所做的那样:'\''意味着:"关闭字符串","转单引号","开始新的字符串"
  • 定义别名时,您通常需要围绕其定义的 引号,以便延迟评估该命令直到别名被调用

其他解决方案及其陷阱

以下根据以下别名讨论替代解决方案:

alias foo='echo A '\''*'\'' is born at $(date)'

注意*如何有效地用单引号括起来 - 使用上述技术 - 以便在以后调用别名时防止路径名扩展。

调用时,此别名会打印 literal A * star is born,然后是然后 - 当前日期和时间,例如:A * is born at Mon Jun 16 11:33:19 EDT 2014


使用名为ANSI C quoting的功能,其中包含支持它的外壳:bashkshzsh

ANSI C引用的字符串,包含在$'...'中,DO允许转义嵌入的'字符。作为\'

alias foo=$'echo A \'*\' is born at $(date)'

<强>陷阱

  • 此功能不属于POSIX。
  • 按照设计,\n\t,...之类的转义序列也被解释(实际上,这是该功能的目的)。

使用交替引用样式,如@ Dropout的回答:

<强>陷阱

'...'"..."具有不同的语义,因此将一个替换为另一个可能会产生意想不到的副作用:

alias foo="echo A '*' is born at $(date)" # DOES NOT WORK AS INTENDED

虽然语法正确,但这不会按预期工作,因为使用 double 引号会导致shell立即扩展命令替换$(date) ,因此 硬连接别名定义时的日期和时间到别名

如上所述:当定义别名时,您通常需要围绕其定义的 引号,以便延迟评估命令,直到别名被调用


最后,警告

类似Bourne的shell环境中的棘手问题是在单引号字符串中嵌入'有时 - 错误地 - 出现工作(而不是生成语法错误,如在问题中),当它做了不同的事情时:

 alias foo='echo a '*' is born at $(date)'  # DOES NOT WORK AS EXPECTED.

此定义已接受(无语法错误),但未按预期工作 - 定义的右侧有效解析为 3 字符串 - 'echo a '*' is born at $(date)',由于shell解析字符串的方式(合并相邻的字符串,引用删除),会产生以下结果, single ,文字字符串:a * is born at $(date)。由于结果别名定义中* 未加引号,因此在调用别名时,它将扩展为当前目录(路径名扩展)中所有文件/目录名称的列表。

答案 1 :(得分:4)

你可以使用不同的引号来包围整个文本和内部字符串。

尝试将其更改为

alias logspace="find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | awk '{print $5, $9 }'"

换句话说,您的外部引号应该与内部引号不同,因此它们不会混合。

答案 2 :(得分:2)

社区维基更新

  • 此答案的兑换功能 认识到OP的问题在于未使用字符串分隔符(' in 字符串即可。
  • 但是,这个答案包含一般字符串处理真相,但不适用于(Bourne-like,POSIX兼容)shell编程具体 ,因此不直接解决OP的问题 - 请参阅评论。

注意:代码段应该是伪代码,而不是shell语言。

基本字符串:您不能在字符串中使用相同的引号,因为整个字符串用以下分隔:

foo='hello, 'world!'';
    ^--start string
            ^-- end string
             ^^^^^^^^--- unknown "garbage" causing syntax error.

你必须转义内部字符串:

foo='hello, \'world!\'';
            ^--escape

这个星球上的每种编程语言都是如此。如果它们不提供转义机制,例如\,则必须使用其他方法,例如

quotechar=chr(39); // single quote is ascii #39
foo='hello ,' & quotechar & 'world!' & quotechar;

答案 3 :(得分:1)

转义$而不是awk的单引号,并使用双引号作为别名。

尝试一下:

alias logspace="find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | awk '{print \$5, \$9 }'"