Unix'alias'使用'awk'命令失败 [英] Unix 'alias' fails with 'awk' command
问题描述
我在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命令失败的任何想法...
谢谢, 肖恩.
以补充 @Dropout的有用答案:>
tl; dr
问题是OP尝试在'
内(单引号)的字符串中使用'
.
在这种情况下,最可靠的解决方案是用'\''
(原文如此)替换每个 interior '
:
alias logspace='find /apps/ /opt/ -type f -size +100M -exec ls -lh {} \; |
awk '\''{print $5, $9 }'\'''
- 类似Bourne的(兼容POSIX的)shell根本不支持在单引号(
'...'
括起来)的字符串中使用'
字符-甚至无法转义.- (相反,您可以在 double 引号中的字符串内将
"
转义为\"
,就像@Droput的答案一样,您可以直接将'
字符嵌入. ,但请参阅下面的陷阱.)
- (相反,您可以在 double 引号中的字符串内将
- 上述解决方案可以有效地从多个单引号字符串中构建字符串,这些字符串将文字
'
转换为字符. -在外部中转义为\'
的单引号字符串-在中拼接 .
另一种表达方式,如@Etan Reisinger在评论中所做的:'\''
表示:关闭字符串",转义单引号",开始新字符串". - 定义别名时,通常需要在其定义周围加上 单引号,以便延迟评估该命令,直到别名被调用.
其他解决方案及其陷阱:
以下内容基于以下别名讨论了替代解决方案:
alias foo='echo A '\''*'\'' is born at $(date)'
请注意如何使用上述技术有效地将*
括在单引号中,以防止在以后调用别名时扩展路径名.
在调用时,此别名显示 literal A * star is born
,后跟 then -当前日期和时间,例如:A * is born at Mon Jun 16 11:33:19 EDT 2014
.
使用称为 ANSI C引用具有支持它的shell:bash
,ksh
,zsh
用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
尽管语法上正确,但这将无法按预期工作,因为使用 double 引号会使外壳程序立即扩展命令替换$(date)
,因此 硬线将别名定义转换为别名时的日期和时间.
如上所述:定义别名时,通常需要在其定义周围加上 单引号,以便延迟评估.命令> strong>,直到别名被调用.
最后,是 caveat :
在类似Bourne的shell环境中,棘手的事情是有时将'
嵌入在单引号中-错误地-似乎可以正常工作(而不是像问题),那么当它做一些不同的事情时:
alias foo='echo a '*' is born at $(date)' # DOES NOT WORK AS EXPECTED.
此定义已被接受(没有语法错误),但无法按预期工作-该定义的右侧被有效地解析为 3 字符串- 'echo a '
,*
和' is born at $(date)'
(由于外壳如何解析字符串(合并相邻的字符串,删除引号))导致以下单文字字符串:*
未用引用,因此在调用别名时,它将扩展为当前目录中所有文件/目录名称的列表(路径名扩展).
I'm creating an alias in Unix and have found that the following command fails..
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...
Thanks, Shaun.
To complement's @Dropout's helpful answer:
tl;dr
The problem is the OP's attempt to use '
inside a '
-enclosed (single-quoted) string.
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.- (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.)
- (By contrast, you CAN escape
- 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". - 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, e.g.: 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-quoted strings, which are enclosed in $'...'
, DO allow escaping embedded '
chars. as \'
:
alias foo=$'echo A \'*\' is born at $(date)'
Pitfalls:
- This feature is not part of POSIX.
- By design, escape sequences such as
\n
,\t
, ... are interpreted, too (in fact, that's the purpose of the feature).
Use of alternating quoting styles, as in @Dropout's answer:
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.
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:
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)
. 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.
这篇关于Unix'alias'使用'awk'命令失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!