我在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命令失败的任何想法......
谢谢,
肖恩。
这是因为你在{print ...之前有'关闭你的字符串。 你需要正确地逃避你的报价。
正确的解决方法是将其声明为函数。 logspace () { find /apps /opt -type f -size +100M -exec ls -lh {} \; | awk '{ print $5, $9 }'; }甚至更好地使用find的内置printf格式来提取所需的字段。
跳过答案中提到的引用钩子的另一种方法是使用shell函数而不是别名,如下所示:stackoverflow.com/a/7244626/15109
如果答案解决了您的问题,请单击旁边的大复选标记(?)接受。 如果您发现其他答案有帮助,请向上投票。 接受和提高投票的答案不仅有助于回答,也有助于未来的读者。 请参阅相关的帮助中心文章。 如果您的问题尚未得到完全解答,请提供反馈。
补充@ Dropout的有用答案:
TL;博士
问题是OP尝试在' - 封闭(单引号)字符串中使用'。
在这种情况下,最强大的解决方案是用'\''(原文如此)替换每个内部':
alias logspace='find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; |
awk '\''{print $5, $9 }'\'''
Bourne-like(POSIX兼容)shell不支持在单引号('...' -enclosed)字符串中使用'字符AT ALL - 甚至不使用转义。
(相比之下,你可以在双引号字符串中以\"的形式转义",并且在@ 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:bash,ksh,zsh
ANSI C引用的字符串,包含在$'...'中,DO允许转义嵌入的'字符。 as \':
alias foo=$'echo A \'*\' is born at $(date)'
陷阱:
此功能不是POSIX的一部分。
通过设计,转义序列如,\t,......也被解释(事实上,这是该功能的目的)。
使用交替引用样式,如@ Dropout的答案:
陷阱:
'...'和"..."具有不同的语义,因此将一个替换为另一个可能会产生意想不到的副作用:
alias foo="echo A '*' is born at $(date)" # DOES NOT WORK AS INTENDED
虽然语法正确,但这不会按预期工作,因为使用双引号会导致shell立即扩展命令替换$(date),从而将别名定义时的日期和时间硬连接到别名中。
如上所述:在定义别名时,通常需要围绕其定义使用单引号,以便延迟对命令的评估,直到调用别名为止。
最后,一个警告:
在类似Bourne的shell环境中,棘手的事情是将'嵌入单引号字符串中 - 有时 - 错误地 - APPEARS工作(而不是产生语法错误,如在问题中),当它改为执行不同的操作时:
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)。由于*在结果别名定义中未加引号,因此在调用别名时,它将扩展为当前目录(路径名扩展)中所有文件/目录名称的列表。
很高兴听到它的帮助,@ VivekAgrawal。
你可以使用不同的引号来包围整个文本和内部字符串。
尝试将其更改为
alias logspace="find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | awk '{print $5, $9 }'"
换句话说,您的外部引号应该与内部引号不同,因此它们不会混合。
是不是关于$?我不得不逃避它在这个例子中工作:alias ip="ifconfig en1 | awk '/inet / { print \$2 }'"
我不得不使用不同的报价来逃避$
在某些情况下,当您混合双引号和单引号时,您会得到奇怪的结果。示例:alias ipconnected ="netstat -tn 2> / dev / null | grep:80 | awk'{print $ 5}'| cut -d:-f1 | sort | uniq -c | sort -nr | head"
社区维基更新:
这个答案的兑换功能是认识到OP的问题在于在字符串内未使用字符串分隔符(')。
但是,这个答案包含一般的字符串处理事实,但并不特别适用于(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;
不幸的是,(Bourne-like)shell语言与地球上的其他编程语言不同:你无法逃脱' chars。在' - 封闭的字符串中,=周围不能有空格。
实际上,正如@ mklement0所说,你不能在单引号内逃避单引号。你唯一能做的就是在某处使用双引号或在每个"嵌入式"单引号上使用(非常难看的)'\''序列。 (即"关闭字符串","转义单引号","启动新字符串"。)
以上代码从未打算被视为bash。它是伪代码,用于显示如何在不采取特殊措施的情况下在字符串中使用引号。
@MarcB:问题标记为linux和shell,并使用alias功能,因此我们清楚地讨论类似Bourne的POSIX兼容shell(其中bash)。您的原始答案(a)建议转义,特别是在手头的情况下不是选项,并且(b)在识别该事实时,然后使用不同语言的语法作为解决方法示例。总而言之,从原始问题的角度来看,这个答案主要是分散注意力,并且需要克服所产生的混乱,以便了解它所包含的一般事实。
@MarcB:我已经再次编辑了答案,希望澄清你的原始意图,同时避免分心方面。
转义$符号而不是awk的单引号,并使用双引号作为别名。
试试这个 :
alias logspace="find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; | awk '{print \$5, \$9 }'"
希望它有效,我不确定alias可以扩展""。让我们知道是否有效。