2011-12-24 23 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