这个问题的不同之处在于经典的"使用函数"答案不起作用。在现有的Alias问题中添加注释相当于向Yahoo发送建议电子邮件
我正在尝试编写宏来绕过BASH可怕的IF语法。你知道,[,[[,(…BASH:流控制的PHP…只是添加了另一个括号。我还在等待"形式。不太确定为什么BASH没有重新调整"("的用途,因为"("在if语句中没有真正的语义。
我们的想法是为[、[[和()命名别名,因为这些经过测试的函数中的每一个都有令人沮丧的不同语法。老实说,我永远记不清哪个是哪个(你怎么可能?这完全是临时的!),祝你好运,试着在谷歌上搜索"[["。
然后,我会使用名称作为助记符,并使用别名来消除间距要求上的巨大差异。例如:"whatdoyoucallthisIf"for"(","shif"(表示shell if),"mysterybdoublesquarebackettif"for那个可怕的[[东西似乎大多和[[做同样的事情,只是它没有。
因此,我必须有某种形式:
alias IFREPLACEMENT="if[\$@];then">
但显然不是\$@,它只会在当前参数列表中与运行别名的shell绑定。
函数将不在这种情况下工作,因为函数:
function IFREPLACEMENT {
if [ $@ ]; then
}
是非法的。
在CSH,你可以说别名abc等等*!1等。BASH中是否有类似的东西(不,!*在BASH中不起作用)?
还是["我只是运气不好"]?
顺便说一句,以下是BASH中涉及测试ish函数的一些令人沮丧的差异,我试图通过使用定义良好的别名来避免这些差异,人们必须使用这些别名,而不是选择错误的"[["、"["或"(":
- "("真的很令人毛骨悚然……如果一个变量包含另一个变量的名称,则会根据需要对其进行多个级别的引用)
- "("不需要像"["one_answers"[["这样的空格
- "("不需要"$"来取消引用变量
- [的"-gt"是数字或数字。[[似乎有任意的限制
- "["one_answers"[["使用">"(等)作为LEXIAL比较运算符,但它们有令人沮丧的不同规则,使其看起来像是在进行数字比较,而实际上并不是
- 对于变量a="(空值),[$a==123]是语法错误,但((a==123))不是
当然,函数可以工作,但不像宏:
function IFREPLACEMENT {
[[ "$@" ]]
}
IFREPLACEMENT "$x" = "$y" && {
echo "the same
}
FWIW,这里有一种将参数传递给别名的残酷方法。
$ alias enumerate='bash -c '''for ((i=0; i<=$#; i++)); do arg=${!i}; echo $i $arg; done''
$ enumerate foo bar baz
0 foo
1 bar
2 baz
很明显,因为生成了一个新的bash shell,所以无论您做什么都不会对当前shell产生任何影响。
更新:根据@konsolebox的反馈,现在建议始终使用[[...]]
,以获得简单性和性能(最初的答案建议((...))
用于数值/布尔测试)。
@Oliver Charlesworth在对该问题的评论中提出了而不是试图隐藏底层bash
语法的理由,我同意。
您可以使用以下规则简化事情:
-
始终使用
[[ ... ]]
进行测试- 如果必须与POSIX兼容,则仅使用
[ ... ]
。如果可用,[[ ... ]]
总是更好的选择(惊喜更少,功能更多,几乎是[1]的两倍) - 使用双引号、前缀为
$
的变量引用-以确保健壮性和简单性(尽管1,但双引号确实会略微降低性能)-例如"$var"
;参见以下关于==
和=~
的RHS的例外情况
- 如果必须与POSIX兼容,则仅使用
-
空白规则:
- 总是在条件词(无论是
[[
/((
还是]]
/))
)的初始分隔符之后和结束分隔符之前加一个空格 - 在变量赋值中,切勿在
=
周围放置空格
- 总是在条件词(无论是
为了简化起见,这些规则的限制性比它们需要的更大。
提示和陷阱:
- 注意,对于数字与
[[ ... ]]
的比较,必须使用-eq
、-gt
、-ge
、-lt
、-le
,因为==
、<
、<=
、>
、>=
用于词汇比较。[[ 110 -gt 2 ]] && echo YES
- 如果要将
==
与模式匹配(globbing)一起使用,请将整个RHS指定为未加引号的字符串,或者至少使特殊globbining字符不加引号。[[ 'abc' == 'a'* ]] && echo YES
- 类似地,执行与
=~
匹配的正则表达式需要整个RHS都不带引号,或者至少保留特殊的正则表达式字符。未引用-如果您使用变量来存储正则表达式-为了避免与Linux上的前缀结构有关的错误,您可能必须这样做-引用未引用的变量。
[[ 'abc' =~ ^'a'.+$ ]] && echo YES
re='^a.+$'; [[ 'abc' =~ $re ]] && echo YES # *unquoted* use of var. $re
-
对于纯数值/布尔测试,
[[ ... ]]
的替代方案是使用算术评估((...))
。其性能与[[
相当(慢约15-20%1);算术评估(参见man bash
中的ARITHMETIC EVALUATION
部分):- 允许C型算术(整数)运算,如
+
、-
、*
、/
、**
、%
- 支持赋值,包括递增和递减操作(
++
/--
) -
变量引用不需要
$
前缀。-
Caveat:在两种情况下,您仍然需要
$
:- 如果要指定基数或执行前置参数扩展,例如删除前缀:
var=010; (( 10#$var > 9 )) && echo YES # mandate number base 10
var=v10; (( ${var#v} > 9 )) && echo YES # strip initial 'v'
- 如果要防止递归变量展开。奇怪的是,
((...)
递归扩展了一个没有$
的变量名,直到它的值不再是现有变量的名称: var1=10; var2=var1; (( var2 > 9 )) && echo YES
var2
扩展为10
(!)
- 如果要指定基数或执行前置参数扩展,例如删除前缀:
-
Caveat:在两种情况下,您仍然需要
- 允许C型算术(整数)运算,如
-
具有较宽松的空白规则。
- 示例:
v1=0; ((v2 = 1 + ++v1)) && echo YES # -> $v1 == 1, $v2 == 2
-
注意:由于算术求值的行为与
bash
的其他部分非常不同,因此您必须权衡其添加的功能与记住一组额外的规则。您还需要支付轻微的性能罚款1 -
你甚至可以把算术表达式,包括赋值,塞进基于数字运算符的
[[
条件中,尽管这可能会变得更加混乱;例如:v1=1 v2=3; [[ v1+=1 -eq --v2 ]] && echo TRUE # -> both $v1 and $v2 == 2
注意:在这种情况下,我所说的"引用"是指对整个字符串进行单引号或双引号引用,而不是对不包含在单引号或两引号中的字符串中的单个字符进行转义
1:以下代码改编自@konsolebox的代码,用于性能测量:
注:
- 结果可能因平台而异-数字基于OS X 10.9.3和Ubuntu 12.04
[[
的速度几乎是[
的两倍(因子约为1.9)基于:- 使用未加引号,
[[
中的$
前缀变量引用(使用双引号变量引用会在一定程度上减慢速度)
- 使用未加引号,
((
比[[
慢,未加引号,两个平台上的$
前缀变量:在OSX上约为15-20%,在Ubuntu上约为30%。在OSX上,使用双引号,前缀为$
的变量引用实际上慢,因为根本不使用$
前缀(与数字运算符一起使用)。相比之下,在Ubuntu上,((
比所有]]
变体都慢
#!/usr/bin/env bash
headers=( 'test' '[' '[[/unquoted' '[[/quoted' '[[/arithmetic' '((' )
iterator=$(seq 100000)
{
time for i in $iterator; do test "$RANDOM" -eq "$RANDOM"; done
time for i in $iterator; do [ "$RANDOM" -eq "$RANDOM" ]; done
time for i in $iterator; do [[ $RANDOM -eq $RANDOM ]]; done
time for i in $iterator; do [[ "$RANDOM" -eq "$RANDOM" ]]; done
time for i in $iterator; do [[ RANDOM -eq RANDOM ]]; done
time for i in $iterator; do (( RANDOM == RANDOM )); done
} 2>&1 | fgrep 'real' | { i=0; while read -r line; do echo "${headers[i++]}: $line"; done; } | sort -bn -k3.3 | awk 'NR==1 { baseTime=substr($3,3) } { time=substr($3,3); printf "%s %s%%n", $0, (time/baseTime)*100 }' | column -t
输出从最快到最慢的时间,较慢的时间也表示为最快时间的百分比。