2013-04-22 91 views
6

對不起,這個蹩腳的bash問題,但我似乎無法解決。Bash最後一個索引

我有以下簡單的例子:

  • 我有可變像artifact-1.2.3.zip

  • 我想得連字符和點的最後一個指數之間的子串(包括獨家)。

我的bash技能不太強。我有以下幾點:

a="artifact-1.2.3.zip"; b="-"; echo ${a:$(($(expr index "$a" "$b" + 1) - $(expr length "$b")))} 

生產:

1.2.3.zip 

如何刪除.zip部分呢?

回答

4
$ a="artifact-1.2.3.zip"; a="${a#*-}"; echo "${a%.*}" 

#模式」刪除模式,只要它符合開始的$a模式的語法與文件名匹配中使用的語法相似。 在我們的例子中,

  • *是任何字符序列。
  • -表示字面短劃線。
  • 因此#*-匹配所有內容,包括第一個短劃線。
  • 因此${a#*-}擴展到任何$a將擴大至, 除了artifact-從擴張取出, 留給我們1.2.3.zip

類似地,「%圖案」刪除圖案,只要它的膨脹匹配。 在我們的案例中,

  • .字面點。
  • *任何字符序列。
  • 因此%.*就是一切,包括最後的點直到字符串的末尾。
  • 因此,如果$a擴大到1.2.3.zip, 然後${a%.*}擴大到1.2.3

工作完成。

本手冊頁內容如下(至少在我的機器,情況因人而異上):

 
     ${parameter#word} 
     ${parameter##word} 
       The word is expanded to produce a pattern just as in pathname 
       expansion. If the pattern matches the beginning of the value of 
       parameter, then the result of the expansion is the expanded 
       value of parameter with the shortest matching pattern (the ``#'' 
       case) or the longest matching pattern (the ``##'' case) deleted. 
       If parameter is @ or *, the pattern removal operation is applied 
       to each positional parameter in turn, and the expansion is the 
       resultant list. If parameter is an array variable subscripted 
       with @ or *, the pattern removal operation is applied to each 
       member of the array in turn, and the expansion is the resultant 
       list. 

     ${parameter%word} 
     ${parameter%%word} 
       The word is expanded to produce a pattern just as in pathname 
       expansion. If the pattern matches a trailing portion of the 
       expanded value of parameter, then the result of the expansion is 
       the expanded value of parameter with the shortest matching pat- 
       tern (the ``%'' case) or the longest matching pattern (the 
       ``%%'' case) deleted. If parameter is @ or *, the pattern 
       removal operation is applied to each positional parameter in 
       turn, and the expansion is the resultant list. If parameter is 
       an array variable subscripted with @ or *, the pattern removal 
       operation is applied to each member of the array in turn, and 
       the expansion is the resultant list. 

HTH!

編輯

榮譽對@ x4d了詳細的解答。 儘管如此,仍然認爲人們應該RTFM。 如果他們不明白手冊, 然後張貼另一個問題。

+0

好又簡單,謝謝! – carlspring 2013-04-22 17:54:35

+5

這裏列出的任何解釋或相關文檔會更好。 – Judking 2015-05-13 08:52:13

+0

RTFM。公平的說,手冊頁非常大。在該文件中查找兩個連續的哈希,並且您將位於右側區域(_less_中的'/ ##'命令) – bobbogo 2015-05-13 09:50:19

0

我認爲你可以這樣做:

string=${a="artifact-1.2.3.zip"; b="-"; echo ${a:$(($(expr index "$a" "$b" + 1) - $(expr length "$b")))}} 

substring=${string:0:4} 

最後一步的最後4個字符從字符串中刪除。還有一些關於here的更多信息。

+0

+1:雖然它會將我和三個字母的擴展名綁定在一起。我會接受bobbogo的回答。謝謝! – carlspring 2013-04-22 17:55:11

+0

謝謝,沒問題,這不是一個非常便攜的解決方案,但我喜歡讓事情簡單:)。 Bobbogo的解決方案是要走的路。 – James 2013-04-22 17:56:36

3

使用bash正則表達式的功能:

>str="artifact-1.2.3.zip" 
[[ "$str" =~ -(.*)\.[^.]*$ ]] && echo ${BASH_REMATCH[1]} 
21

標題bash手冊頁節 「變量替換」 使用${var#pattern}${var##pattern}${var%pattern}${var%%pattern}描述。

假設你有一個叫filename變量,例如,

filename="artifact-1.2.3.zip" 

那麼,下面是基於模式的提取:

% echo "${filename%-*}" 
artifact 

% echo "${filename##*-}" 
1.2.3.zip 

爲什麼我用##代替#

如果文件名可能可能包含內破折號,如:

filename="multiple-part-name-1.2.3.zip" 

然後比較兩個以下取代:

% echo "${filename#*-}" 
part-name-1.2.3.zip 

% echo "${filename##*-}" 
1.2.3.zip 

一旦已經提取出的版本和擴展,以隔離的版本,使用方法:

% verext="${filename##*-}" 
% ver="${verext%.*}" 
% ext="${verext##*.}" 
% echo $ver 
1.2.3 
% echo $ext 
zip 
+0

我也會試試這個!感謝您的詳細描述。 – carlspring 2013-04-22 18:35:23

相關問題