2011-12-24 18 views
1

我正在尝试获取下一个四分之一的第一天,例如现在我想要获得00:01 2012-01-01。它不应该太难。但是我因语法错误而停滞不前,因为我无法正确地转义所有内容。在bash中使用expr的语法错误

为了得到正确的一个月,我想用:

expr `date "+((%m - 1)/3 + 1) * 3 % 12 + 1"` 

的部分(%m - 1)/3 + 1计算当前quartal的数量。 但是,*似乎在某种程度上是错误的。如果我将其替换为+,则不会出现语法错误(结果对我而言并不重要)。我试图通过使用\*逃脱*,但这没有帮助。我想反引号存在一些问题。

我怎样才能正确逃避*

编辑: 我的问题已经解决了,但是我想补充别人一个短的警告。请注意,如果您想直接在日期中使用它,并且还要关心正确的一年,则还需要为该月添加前导零。所以在一天结束时,paxdiablo的建议可能是最简单的。

回答

2
$ date "+((%m - 1)/3 + 1) * 3 % 12 + 1" | xargs expr 
1 
0

用双引号括起你的整个表情:问题是你的命令替换中有空格,请不要expr

这就产生了一个号码,不过我估计你可以用算术评估更有效地存在:

[email protected] ~ $ expr "`date "+((%m - 1)/3 + 1) * 3 % 12 + 1"`" 
((12 - 1)/3 + 1) * 3 % 12 + 1 
[email protected] ~ $ echo $(($(expr "`date "+((%m - 1)/3 + 1) * 3 % 12 + 1"`"))) 
1 
+0

你的意思是哪个空格? – lumbric 2011-12-24 12:21:38

+0

您在'date'命令中使用的格式会产生空格。但'expr'只允许某些形式的空格参数。它不会允许使用'(expr)* something',这就是为什么你在星号上得到错误。 – fge 2011-12-24 12:31:06

+0

我不认为这是一个问题。其实我需要'expr'的空格。否则'expr'只是返回字符串的输入(就像在你的代码中的第一行)。 – lumbric 2011-12-24 12:47:22

1

可以使用set禁用水珠扩展,运行的计算和重新启用水珠扩展:

set -o noglob 
expr `date "+((%m - 1)/3 + 1) * 3 % 12 + 1"` 
set +o noglob 
3

如果您不介意编码bash功能来做到这一点,您可以使用类似下面的东西getNextQuarter功能离子:

# getNextQuarter - returns YYYY-MM-DD for the first day of the next quarter. 
getNextQuarter() { 
    m="$(date +%m)" 
    case $m in 
     '01' | '02' | '03') echo "$(date +%Y)-04-01" ;; 
     '04' | '05' | '06') echo "$(date +%Y)-07-01" ;; 
     '07' | '08' | '09') echo "$(date +%Y)-10-01" ;; 
     '10' | '11' | '12') echo "$(expr $(date +%Y) + 1)-01-01" ;; 
    esac 
} 

nq=$(getNextQuarter) 
echo $nq 

即使在一个shell脚本,你应该考虑,可以使用在隐蔽可能单行良好的命名函数来获得可读性的改进。

现在,这可能不会是盲目快速的,但说实话,如果速度是您最关心的问题,我会重新审视shell脚本。

想想别人(甚至是你六个月后)会在查看代码时想到你的代码。我喜欢假设那些不得不维护我的代码的人是知道我住在哪里的精神病患者。

+0

恐怕,那可能是真的。我的代码将不再可读。但说实话...什么让你更满意?带有长硬编码列表或*真实*计算的'case'命令,它们的结果正是你想要的? ;) – lumbric 2011-12-24 12:51:04

+0

@lumbric,是的,即使经过了这么多十年,我有时候仍然会从“聪明”的代码中获得成就感,但作为一名专业人员,我付出的是提供质量而不是聪明。并不是说他们总是互相排斥。 – paxdiablo 2011-12-24 16:42:22

+0

即使是神秘的单行者,也可以通过单一评论变得更加清晰。 – 2011-12-24 18:14:04

1

第一个问题是*按日期输出后被认为是通配符。我用$[](相当于$(())而不是expr解决了这个问题。

第二个问题(至少在这里在Mac OS X)是,“%”需要使用转义“%%”(这是迄今为止的所有版本有效):

$ echo $(($(date "+((%m - 1)/3 + 1) * 3 %% 12 + 1"))) 
1 

我发现另一种是使用eval,正确转义括号后:

$ eval "expr $(date "+\(\(%m - 1 \)/3 + 1 \) '*' 3 %% 12 + 1")" 

不同方式可以零填充使用printf

$ printf "%02d\n" $(($(date "+((%m - 1)/3 + 1) * 3 %% 12 + 1"))) 
01 
$ printf "%02d\n" $(eval "expr $(date "+\(\(%m - 1 \)/3 + 1 \) '*' 3 %% 12 + 1")") 
01 
+0

啊,这是一个很好的方式,我没有想到这一点。用bash不需要转义'%'。至少这是我测试的结果。 – lumbric 2011-12-25 15:14:19

+0

日期,而不是shell,涉及处理%或%%; %使用非GNU版本的日期时需要转义 - 这里在Mac OS X上我有两种版本的日期安装,我可以验证不同之处。无论如何,我建议%%,因为它更便携。 – Blaisorblade 2011-12-30 15:43:11