2013-07-21 81 views
0

我寫了一個腳本來簡化運行長啓動命令:

# in ~/.bash_profile 
function runProgram() { sbt "run-main com.longpackagename.mainclass [email protected] arg3"; }; 
export -f runProgram; 

然而,失敗的時候我試圖通過多個參數:

$ runProgram arg1 arg2 
... 
[info] Running com.longpackagename.mainclass arg1 

什麼碰巧arg2和arg3?他們是被bash還是被sbt吃掉了?

腳本作品,如果我運行像這樣的預期:

$ runProgram "arg1 arg2" 

-

此外:這類問題發生的時間對我來說。我也很感謝有關如何在bash中正確地轉義的參考。 first & second我試過的資源沒有解決這種情況。

+0

爲什麼是,他們*被'sbt'吃掉了。引用本身並不會幫助你。 –

回答

3

bash的最佳參考(包括引用的工作方式)是bash手冊本身,它幾乎可以安裝在您的機器上,您可以通過輸入man bash而無需互聯網連接即可閱讀。閱讀起來很多,但沒有真正的替代品。

儘管如此,我會盡力解釋這個特殊問題。有兩件重要的事情需要知道:首先,bash如何(以及何時)將命令行分割爲單獨的「單詞」(或命令行參數);第二,什麼[email protected]$*的意思。這些並不完全無關。

分詞部分由特殊參數IFS控制,但我只是提到這一點;我假設它沒有被改變。有關更多詳細信息,請參閱man bash

下面,我打電話引用用雙引號("..."弱引用一個字符串,用單引號('...'強引用引用。反斜槓(\)也是一種強烈的引用形式。

字分裂發生的情況:

  1. 後參數(殼變量)被取代成它們的值,

  2. 只要有空白字符的序列,

  3. 除非以任何方式引用空格(" ",' ',\是三種方式),

  4. 在報價被刪除之前。

一旦命令已經被分成的話,第一個詞被用來尋找程序或函數來調用,且剩餘的詞成爲程序的參數。 (我忽略了許多像shell元字符,重定向,管道等等的東西。有關更多詳細信息,請參閱man bash。)

參數取代有它們的值(步驟1)如果它們的名稱是由前面$除非$name強烈引用(即,'$name'或,例如,\$name)。還有更多形式的參數替換。有關更多詳細信息,請參閱man bash

現在,[email protected]$*都表示「當前命令/函數的所有位置參數」,並且如果它們沒有引號使用,則它們完全相同。它們被所有的位置參數取代,每個參數之間有一個空格。由於這是一種參數替換(如上所述),所以在替換後發生分詞,除非替換用引號引起,如上面的列表中所示。

如果替換是用引號括起來的,那麼根據上述規則,在參數之間插入的空格不受分詞的限制。這正是$*的工作原理。 $*被空格分隔的命令行參數取代,結果是分詞; "$*"被空格分隔的命令行參數替換爲單個單詞。

"[email protected]"是一個例外。事實上,這就是爲什麼[email protected]存在。如果[email protected]位於弱引號內("[email protected]"),則刪除引號,並且單獨引用每個位置參數的。這些引用的位置參數然後被間隔分開並代替[email protected]。由於[email protected]不再被引用,插入的空格確實會導致分詞。最終的結果是個別參數保留爲單個詞。

如果不是完全清楚的話,下面是一個例子。 printf具有重複提供的格式的優點,直到它用完參數,這使得很容易看到發生了什麼。

showargs() { 
    echo -n '$*: '; printf "<%s> " $*; echo 
    echo -n '"$*": '; printf "<%s> " "$*"; echo 
    echo -n '"[email protected]": '; printf "<%s> " "[email protected]"; echo 
} 

showargs one two three 
showargs "one two" three 

(揣摩你執行它之前是什麼打印。)

人們常常說,你幾乎總是需要"[email protected]",幾乎從不"[email protected]"$*。這通常是正確的,但也是這種情況,你幾乎從不想要"something with [email protected] inside of it"。要了解這一點,您需要知道"something with [email protected] inside of it"的作用。這有點奇怪,但它不應該是意想不到的。我們將採取的sbt調用從OP作爲一個例子:

sbt "run-main com.longpackagename.mainclass [email protected] arg3" 

與提供給函數的兩個位置參數,以使得$1arg1$2arg2

首先,bash刪除[email protected]左右的引號。但是,它不能完全刪除它們,因爲那裏也有引用文本。因此,它具有事後封閉引用的文本並重新打開引號,生產:

sbt "run-main com.longpackagename.mainclass "[email protected]" arg3" 

現在,它可以在所列出的,間隔分開的參數代替:

sbt "run-main com.longpackagename.mainclass ""arg1" "arg2"" arg3" 

這是現在字處理駁:

sbt 
"run-main com.longpackagename.mainclass ""arg1" 
"arg2"" arg3" 

和引號被刪除:

sbt 
run-main com.longpackagename.mainclass arg1 
arg2 arg3 

sbt僅需要一個位置參數。你給了它兩個,它忽略了第二個。

現在,假設函數是用一個參數"arg1 arg2"調用的。在這種情況下,的[email protected]結果在替代:

sbt "run-main com.longpackagename.mainclass ""arg1 arg2"" arg3" 

和字分割產生

sbt 
"run-main com.longpackagename.mainclass ""arg1 arg2"" arg3" 

沒有引號:

sbt 
run-main com.longpackagename.mainclass arg1 arg2 arg3" 

和只存在一個用於sbt位置參數。