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

Boa*_*411 16 linux shell awk

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

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

我得到以下内容:

awk: cmd. line:1: {print
awk: cmd. line:1:       ^ unexpected newline or end of string
Run Code Online (Sandbox Code Playgroud)

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

谢谢,肖恩.

mkl*_*nt0 40

补充@ Dropout的有用答案:

TL;博士

问题是OP的尝试使用' 内一个'-enclosed(单引号)的字符串.

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

alias logspace='find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | 
                awk '\''{print $5, $9 }'\'''
Run Code Online (Sandbox Code Playgroud)
  • Bourne-like(POSIX兼容)shell不支持'在单引号('...'-enclosed)字符串中使用字符AT ALL - 甚至不使用转义.
    • (相比之下,你可以"在一个双引号字符串中逃脱\",并且,就像@ Droput的回答一样,你可以直接'在那里嵌入字符,但是请看下面的陷阱.)
  • 上面的解决方案有效地从多个单引号字符串构建字符串到其中的文字'字符.- 在单引号字符串之外转义\'- 被拼接.
    另一种方式,就像@Etan Reisinger在评论中所说的那样:'\''意思是:"关闭字符串","逃避单引号","开始新字符串".
  • 在定义别名时,通常需要围绕其定义使用单引号,以便延迟对命令的评估,直到调用别名为止.

其他解决方案及其缺陷:

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

alias foo='echo A '\''*'\'' is born at $(date)'
Run Code Online (Sandbox Code Playgroud)

请注意如何*使用上述技术有效地将其括在单引号中,以便在以后调用别名时防止路径名扩展.

当被调用时,这个别名打印的文字 A * star is born,随后再 -CURRENT日期和时间,例如:A * is born at Mon Jun 16 11:33:19 EDT 2014.


使用一个称为ANSI C报价与支持它的壳:bash,ksh,zsh

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

alias foo=$'echo A \'*\' is born at $(date)'
Run Code Online (Sandbox Code Playgroud)

陷阱:

  • 此功能不是POSIX的一部分.
  • 按照设计,逃避如序列\n,\t,...解释,也(其实,这是该功能的目的).

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

陷阱:

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

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

虽然语法正确的,这将不会按预期进行,因为使用双引号使shell扩展命令替换$(date) 马上,因而硬连线的别名时的日期和时间定义为别名.

如上所述:在定义别名时,通常需要围绕其定义使用单引号,以便延迟对命令的评估,直到调用别名为止.


最后,一个警告:

在类似Bourne的shell环境中,棘手的事情是嵌入'单引号字符串有时 - 错误地 - 使用它来生成(而不是像在问题中那样生成语法错误),当它改为执行不同的操作时:

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

这个定义是公认的(没有语法错误),但不会按预期工作-定义的右侧被有效地解析为3串- 'echo a ',*和' is born at $(date)',其中,由于shell如何解析字符串(合并相邻串,引用删除),结果如下,单个,文字字符串:a * is born at $(date).由于*是加引号的产生别名定义,将扩大到当前目录(路径扩展)的所有文件/目录名的列表.


Mar*_*c B 2

社区维基更新:

  • 这个答案的可取之处是认识到OP的问题在于字符串中字符串分隔符( ')的未转义使用。
  • 然而,这个答案包含一般的字符串处理事实,但不适用于(类似 Bourne 的、POSIX 兼容的)shell 编程,因此不能直接解决 OP 的问题- 请参阅评论。

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

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

foo='hello, 'world!'';
    ^--start string
            ^-- end string
             ^^^^^^^^--- unknown "garbage" causing syntax error.
Run Code Online (Sandbox Code Playgroud)

您必须转义内部字符串:

foo='hello, \'world!\'';
            ^--escape
Run Code Online (Sandbox Code Playgroud)

地球上几乎所有编程语言都是如此。如果它们不提供转义机制,例如\,那么您必须使用替代方法,例如

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

  • 不幸的是,(类似 Bourne 的)shell 语言与地球上所有其他编程语言不同:你无法转义 ''' 字符。在“”括起来的字符串中,并且“=”周围不能有空格。 (2认同)
  • 事实上,正如 @mklement0 所说,你不能像这样在单引号内转义单引号。您唯一能做的就是在某处使用双引号,或者在每个“嵌入”单引号处使用(非常丑陋的)“\”'`序列。(即“关闭字符串”、“转义单引号”、“开始新字符串”。) (2认同)