简体   繁体   English

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

[英]Unix 'alias' fails with 'awk' command

I'm creating an alias in Unix and have found that the following command fails.. 我在Unix中创建了一个别名,发现以下命令失败了..

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

I get the following : 我得到以下内容:

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

Any ideas on why the piped awk command fails... 关于为什么管道awk命令失败的任何想法......

Thanks, Shaun. 谢谢,肖恩。

To complement's @Dropout's helpful answer : 补充@ Dropout的有用答案

tl;dr TL;博士

The problem is the OP's attempt to use ' inside a ' -enclosed (single-quoted) string. 问题是OP尝试使用' 内部 '封闭(单引号)字符串。

The most robust solution in this case is to replace each interior ' with '\\'' (sic): 在这种情况下, 最健壮的解决方案是替换每个内部 ''\\'' (原文如此):

alias logspace='find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | 
                awk '\''{print $5, $9 }'\'''
  • Bourne-like (POSIX-compatible) shells do not support using ' chars inside single-quoted ( '...' -enclosed) strings AT ALL - not even with escaping . 类似Bourne(POSIX兼容)弹不支持使用' (内单引号字符'...' -enclosed)串在所有-即使不是逃避
    • (By contrast, you CAN escape " inside a double -quoted string as \\" , and, as in @Droput's answer, you can directly, embed ' chars. there, but see below for pitfalls.) (相比之下,你能逃脱" -quoted字符串作为内部\\" ,并且,如@ Droput的回答,您可以直接嵌入'字符。在那里,但请参阅下面的陷阱。)
  • The solution above effectively builds the string from multiple, single-quoted strings into which literal ' chars. 上面的解决方案有效地从多个单引号字符串构建字符串,字符串为'字符”。 - escaped outside the single-quoted strings as \\' - are spliced in . - 在单引号字符串之外转义为\\' - 拼接在一起
    Another way of putting it, as @Etan Reisinger has done in a comment: '\\'' means: "close string", "escape single quote", "start new string". 另一种表达方式,正如@Etan Reisinger在评论中所做的那样: '\\''表示:“关闭字符串”,“转单引号”,“启动新字符串”。
  • When defining an alias , you usually want single quotes around its definition so as to delay evaluation of the command until the alias is invoked . 定义别名时 ,通常需要围绕其定义使用引号 ,以便延迟对命令的评估 ,直到调用别名为止。

Other solutions and their pitfalls : 其他解决方案及其缺陷

The following discusses alternative solutions, based on the following alias: 以下讨论基于以下别名的替代解决方案:

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

Note how the * is effectively enclosed in single quotes - using above technique - so as to prevent pathname expansion when the alias is invoked later. 注意*如何有效地用单引号括起来 - 使用上面的技术 - 以便在以后调用别名时防止路径名扩展。

When invoked, this alias prints literal A * star is born , followed by the then -current date and time, eg: A * is born at Mon Jun 16 11:33:19 EDT 2014 . 当被调用时,这个别名打印文字 A * star is born ,然后是当时的日期和时间,例如: A * is born at Mon Jun 16 11:33:19 EDT 2014


Use a feature called ANSI C quoting with shells that support it: bash , ksh , zsh 使用名为ANSI C引用的功能以及支持它的shell: bashkshzsh

ANSI C-quoted strings, which are enclosed in $'...' , DO allow escaping embedded ' chars. ANSI C引用的字符串, 包含在$'...' ,DO允许转义嵌入的'字符。 as \\' : 作为\\'

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

Pitfalls : 陷阱

  • This feature is not part of POSIX. 此功能不是POSIX的一部分。
  • By design, escape sequences such as \\n , \\t , ... are interpreted, too (in fact, that's the purpose of the feature). 通过设计,转义序列如\\n\\t ,...也被解释(事实上,这是该功能的目的)。

Use of alternating quoting styles , as in @Dropout's answer: 使用交替引用样式 ,如@ Dropout的答案:

Pitfall : 陷阱

'...' and "..." have different semantics , so substituting one for the other can have unintended side-effects: '...'"..."具有不同的语义 ,因此将一个替换为另一个可能会产生意想不到的副作用:

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

While syntactically correct, this will NOT work as intended, because the use of double quotes causes the shell to expand the command substitution $(date) right away , and thus hardwires the date and time at the time of the alias definition into the alias . 虽然语法正确的,这将不会按预期进行,因为使用了引号,shell会展开命令替换$(date) 向右走 ,因而硬连线的别名定义成别名时的日期和时间

As stated: When defining an alias , you usually want single quotes around its definition so as to delay evaluation of the command until the alias is invoked . 如上所述:在定义别名时 ,通常需要围绕其定义使用引号 ,以便延迟对命令的评估 ,直到调用别名为止。


Finally, a caveat : 最后,一个警告

The tricky thing in a Bourne-like shell environment is that embedding ' inside a single-quoted string sometimes - falsely - APPEARS to work (instead of generating a syntax error, as in the question), when it instead does something different: 在一个类似Bourne shell环境的棘手的事情是嵌入'单引号字符串中有时-错误-似乎工作 (而不是产生一个语法错误,因为在这个问题),当它反而就不一样了:

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

This definition is accepted (no syntax error), but won't work as expected - the right-hand side of the definition is effectively parsed as 3 strings - 'echo a ' , * , and ' is born at $(date)' , which, due to how the shell parses string (merging adjacent strings, quote removal), results in the following, single , literal string: a * is born at $(date) . 这个定义被接受 (没有语法错误),但不会按预期工作 - 定义的右侧被有效地解析为3个字符串 - 'echo a '*' is born at $(date)' ,由于shell解析字符串(合并相邻的字符串,引用删除),导致以下单个字面字符串: a * is born at $(date) Since the * is unquoted in the resulting alias definition, it will expand to a list of all file/directory names in the current directory (pathname expansion) when the alias is invoked. 由于*在生成的别名定义中未加引号 ,因此在调用别名时,它将扩展为当前目录(路径名扩展)中所有文件/目录名称的列表。

You chould use different quotes for surrounding the whole text and for inner strings. 你可以使用不同的引号来包围整个文本和内部字符串。

Try changing it to 尝试将其更改为

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

In other words, your outer quotes should be different than the inner ones, so they don't mix. 换句话说,您的外部引号应该与内部引号不同,因此它们不会混合。

Community wiki update : 社区维基更新

  • The redeeming feature of this answer is recognizing that the OP's problem lies in unescaped use of the string delimiters ( ' ) inside a string . 这个答案的可取之处是认识到OP的问题就出在转义使用字符串分隔符(的' )在字符串
  • However, this answer contains general string-handling truths, but does NOT apply to (Bourne-like, POSIX-compatible) shell programming specifically , and thus does not address the OP's problem directly - see the comments. 然而, 这个答案一般包含字符串处理的真理,但并不适用于(类似Bourne,POSIX兼容)shell编程明确 ,因而不能直接解决了OP的问题-看评论。

Note: Code snippets are meant to be pseudo code , not shell language. 注意:代码片段是伪代码 ,而不是shell语言。

Basic strings: You canNOT use the same quote within the string as the entire string is delimited with: 基本字符串:您不能在字符串中使用相同的引号,因为整个字符串是用以下分隔的:

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

You have to escape the internal strings: 你必须转义内部字符串:

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

This is true of pretty much EVERY programming language on the planet. 这对于地球上几乎每种编程语言都是如此。 If they don't provide escaping mechanisms, such as \\ , then you have to use alternate means, eg 如果它们不提供转义机制,例如\\ ,则必须使用其他方法,例如

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

Escape the $ sign not the awk's single quotes and use double quotes for the alias. 转义$符号而不是awk的单引号,并使用双引号作为别名。

Try this : 试试这个 :

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM