2013-04-10 90 views
3

我想在一個腳本來創建一個別名,像這樣:設置別名

#!/bin/bash 
shopt -s expand_aliases 

#Currently just using 'git' to try and get it working 
#It'll be replaced with the following line when it works 
#compgen -c | while read x; 
echo 'git' | while read x; 
    do 
    a=`echo $x | tr '[:lower:]' '[:upper:]'`; 
    echo $a; 
    echo $x; 
    if [ "$a" != '' ] 
    then 
     echo 'got here'; 
     alias $a=$x; 
     alias; 
     GIT; 
    fi 
done 

而一個簡單的測試腳本作品(testme添加到別名在我當前的shell):

從第一腳本
#!/bin/bash 
shopt -s expand_aliases 
alias testme="echo It Worked" 
alias 
testme 

輸出:

GIT 
git 
got here 
alias GIT='git' 
alias grep='grep --colour=auto' 
alias ls='ls --color=auto' 
GIT: command not found 

GIT在別名顯示了,BU t不能執行。我試過用. ./script.shsource script.sh來調用它。我究竟做錯了什麼?

+1

你不應該依賴腳本中的別名。你應該直接使用變量。但如果你仍然想要別名,也許這可以幫助:http://stackoverflow.com/questions/5240755/how-to-use-aliases-defined-in-bashrc-in-shell-script – Lynch 2013-04-10 03:27:29

+0

腳本的整個觀點是*設置別名,不運行它。這有點無用,但很有趣! – SomeKittens 2013-04-10 13:21:34

回答

7

當別名被擴展時,這可能是的問題。 bash手冊頁有以下說:

關於別名的定義和使用的規則有點 混亂。在執行該行上的任何命令之前,Bash總是讀取至少一個完整的輸入行。讀取命令 時不擴展別名,而不是在執行時。 ...

有手冊頁的詳細信息,但在執行一個複合語句,如您while循環內的列表時,當輸入是第一次讀的時候,而不是在執行時會發生膨脹。由於GIT在輸入讀取時未定義,因此會出現錯誤。

以下片段展示了這個問題:

#!/bin/bash 
shopt -s expand_aliases 

while read x; do 
    a=`echo $x | tr '[:lower:]' '[:upper:]'` 
    alias $a=$x 
    GIT # <--- this fails to execute git 
done < <(echo 'git') 

GIT # <--- this executes git 

一旦while循環已經執行,那麼別名變爲可用。手冊頁中的詳細信息有點粗略,但看起來就好像在函數中定義的別名註釋一樣。

另外,使用諸如echo foo | while read x; do stuff; done等語法時要小心。 while循環將在子shell中執行,在子shell中所做的任何更改將不會持續超出while循環。上面的例子顯示了一個方法,以便while循環在當前shell中執行,但是從執行的命令獲取其輸入。

更新:

如果上面的腳本寫在它的原始形式,它應該是這樣的:

#!/bin/bash 
shopt -s expand_aliases 

#Currently just using 'git' to try and get it working 
#It'll be replaced with the following line when it works 
#compgen -c | while read x; 

echo 'git' | while read x; do 
    a=`echo $x | tr '[:lower:]' '[:upper:]'` 
    alias $a=$x 
    GIT # <--- this fails to execute git 
done 

GIT # <--- this also fails executes git because the alias' were set in a subshell. 

在這種情況下,永遠不會執行的別名。原因在於管道|帶來了一個新的子shell並將這些進程鏈接在一起。 echo在一個過程中運行,while read ...在另一個過程中運行,通過管道鏈接。當別名被設置時,它們被設置在運行while循環的子shell的進程的環境中。但是,當while循環結束時,該進程將終止並丟棄其環境,同時對其環境進行任何更改(例如添加別名)。因此,第二次嘗試執行GIT將失敗,因爲別名信息已被丟棄。

當您使用第一個腳本中顯示的拓撲時,while循環會在當前腳本中運行,因此對環境所做的任何更改都會持續到循環結束。

如果您的腳本執行而不是採購它,您也會注意到此行爲。如果您希望能夠像這樣在腳本中配置一組別名,請運行該腳本,讓它們在您的環境中可用,您也會遇到同樣的問題,因爲您的腳本在父shell的獨立進程中運行,創建別名,這些腳本隨後在腳本退出時被丟棄。

$ ./create_aliases 
$ alias # <--- Ooops, no aliases defined. 

您必須像這樣來源腳本,它將運行當前進程中腳本的內容,從而修改當前環境。

$ source ./create_aliases 
$ alias # <--- Yay, new aliases present. 

這就是爲什麼bash將源文件如~/.bashrc,這樣改變了你在該文件中作出將在當前環境中存在。

+0

優秀!我認爲這可能與子shell有關,但無法弄清楚(對於bash腳本來說是非常新穎的)。你能否詳細解釋一下'<(echo'git')'如何在當前shell中執行'while'? – SomeKittens 2013-04-10 13:24:03

+1

@SomeKittens答案更新。 – 2013-04-10 23:41:02