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

我在Unix中创build一个别名,并发现以下命令失败..

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 

有关为什么pipe道awk命令失败的任何想法…

谢谢,肖恩。

补充@ Dropout的有用答案 :

TL;博士

问题在于OP试图使用' 内部 ' (包括单引号)的字符串。

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

 alias logspace='find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | awk '\''{print $5, $9 }'\''' 
  • Bourne-like(POSIX-compatible)shell不支持在单引号( '...' …'-enclosed)字符串内部使用字符 – 甚至不用转义
    • (相比之下,你可以在引号字符串里面跳出" \" ,就像在@ Droput的答案中一样,你可以直接在里面嵌入字符,但是在下面可以看到陷阱。
  • 上面的解决方案从多个单引号字符串中有效地构建字符串,字符串是字符。 – 单引号字符串之外的字符串被“ 拼接”
    另一种方式,如@Etan Reisinger在评论中所做的: '\''表示:“关闭字符串”,“转义单引号”,“开始新字符串”。
  • 定义别名时 ,通常需要在其定义的周围使用引号 ,以便延迟对命令的评估 ,直到调用别名为止。

其他解决方案及其缺陷

以下讨论替代解决方案,基于以下别名:

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

请注意,如何将*有效地用单引号引起来 – 使用上述技术 – 以防止别名稍后被调用时的路径名扩展。

当被调用的时候,这个别名会打印A * star is born 文字 ,然后是当前的日期和时间,例如: A * is born at Mon Jun 16 11:33:19 EDT 2014


使用一个叫做ANSI C的特性来引用支持它的shell: bashkshzsh

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

 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 

虽然在语法上是正确的,但这不会按预期工作,因为使用引号会导致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解析字符串的方式(合并相邻的字符串,引用移除),结果是以下单个字符串: a * is born at $(date) 。 由于*在生成的别名定义中未加引号 ,因此它将展开到当前目录(路径名扩展)中的所有文件/目录名称的列表。

你应该使用不同的引号围绕整个文本和内部的字符串。

尝试改变它

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

换句话说,你的外部报价应该与内部报价不同,所以他们不会混合。

社区wiki更新

  • 这个答案的兑现特征认识到OP的问题在于在字符串内部不使用字符串分隔符( '
  • 然而, 这个答案包含了一般的字符串处理事实,但是并不适用于(类似Bourne的,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;