Shell學習筆記

嘛,作為習慣使用Mac作為開發(fā)系統(tǒng)的開發(fā)者,Shell算是必須學習的內(nèi)容之一。CI的腳本之類的也需要用Shell來寫,總之學習一下沒有壞處。本文主要以基礎(chǔ)的Bourne Shell為學習對象,記錄學習過程中的一些知識要點,和其他筆記一樣,基本上是寫給自己看的,不喜歡的不要拍磚。

1.關(guān)于 #!

'#'表示注釋,而'#!'則告訴系統(tǒng)當前文件應(yīng)該用什么來執(zhí)行。
例如:

#!/bin/sh
echo Hello World

/bin/sh是Bourne shell在Unix下的標準路徑,如果是Linux下,它則是一個指向bash(最新版是dash)的軟連接。

2.關(guān)于chmod

對用戶創(chuàng)建的文件來說,默認只有讀寫權(quán)限,沒有執(zhí)行權(quán)限。為了讓腳本可以被執(zhí)行,就需要通過chmod命令修改權(quán)限。

r 表示讀權(quán)限 用數(shù)字表示為4
w 表示寫權(quán)限 用數(shù)字表示為2
x 表示執(zhí)行權(quán)限 用數(shù)字表示為1
- 表示無權(quán)限 用數(shù)字表示為0

chmod 777 test.sh

3.變量賦值

變量在賦值的時候沒有空格,否則系統(tǒng)會以為這是一條執(zhí)行命令語句,例如:

#!/bin/sh
MY_MESSAGE="Hello World"
echo $MY_MESSAGE

如果=左右有空格的話,系統(tǒng)還以為MY_MESSAGE是一個命令,而=和“Hello world”是命令的兩個參數(shù)。
如果變量沒有被賦值,那么變量將被視為一個空字符串。

4.使用read命令

read命令可以從標準輸入中讀取一行并將其賦值給你提供的變量。

#!/bin/sh
echo "What is your name?"
read MY_NAME
echo "Your name is $MY_NAME"

注意到read命令能夠自動給你的輸入加一對雙引號,這意味著你可以安全的使用空格。

What is your name?
Grand Kindom
Your name is Grand Kindom

5.變量的作用域

一般來說,變量的作用域只限于當前的shell環(huán)境,也就是#!bin/sh之下的環(huán)境中。
例如,我們有如下的shell腳本:

#!/bin/sh
echo "MY_VAR is $MY_VAR"
MY_VAR="Hello"
echo "MY_VAR is $MY_VAR"

現(xiàn)在我們執(zhí)行腳本:

$ MY_VAR=hello
$ ./test.sh
MY_VAR is
MY_VAR is Hello

可以發(fā)現(xiàn),我們在交互式shell(interactive shell)下賦值的變量,對新生成的用來運行腳本的子shell環(huán)境沒有任何影響。
為了能讓子shell可以使用我們的變量,需要使用export命令允許子shell繼承變量。

$ MY_VAR=World
$ export MY_VAR
$ ./test.sh
MY_VAR is World
MY_VAR is Hello

腳本中的第三行,我們更改了MY_VAR變量的值,我們嘗試在交互式shell下輸出:

$ echo $MY_VAR
World

發(fā)現(xiàn)值并沒有發(fā)生任何變化,也就是說子shell對父shell的變量沒有影響。
為了做到這點,我們需要將腳本在當前的交互式shell中運行,而不是新生成一個shell來運行。這一過程叫做source。通過.命令,我們可以source一個腳本:

$ . ./test.sh
MY_VAR is World
MY_VAR is Hello
$ echo $MY_VAR
Hello

MY_VAR變量被成功改變了!這也是.profile.bashrc的工作原理。

6.變量的邊界

考慮以下腳本

#!/bin/sh
echo "Please tell your name"
read MY_NAME
echo "Hello $MY_NAME"
echo "Now I will create a file called $MY_NAME_file"
touch "$MY_NAME_file"

文件能夠創(chuàng)建成功嗎?不行。因為shell不知道變量的起始位置,它還以為有一個變量的名字叫做'MY_NAME_file',而事實上并沒有這樣的一個變量,因此文件創(chuàng)建失敗了。
使用花括號可以界定變量的邊界,他告訴shell:花括號內(nèi)的是一個變量,需要單獨對待。

echo "Please tell your name"
read MY_NAME
echo "Hello $MY_NAME"
echo "Now I will create a file called ${MY_NAME}_file"
touch "${MY_NAME}_file"

再次運行上述修改后的腳本,我們會發(fā)現(xiàn)文件被成功創(chuàng)建。

為什么touch命令的參數(shù)要用雙引號圈起來呢?這是為了防止你輸入的名字有空格。比如說你輸入的名字是Grand Kindom,那么最后的touch命令就會變成touch Grand Kingdom_file。結(jié)果會生成兩個文件,一個叫做Grand,另一個叫做Kindom_file。

7.循環(huán)

1)for循環(huán)

for i in hello 1 * 2 world
do
  echo "i is set to $i in the loop now"
done

2)while循環(huán)

INPUT_STRING=hello
while [ "$INPUT_STRING" != "bye" ]
do
  echo "Please type something in (bye to quit)"
  read INPUT_STRING
  echo "You typed: $INPUT_STRING"
done

當while后跟著一個:時,條件表達式永遠為true,這在某些情況下很有用。

while :
do
  echo "Please type something int (^C to quit)"
  read INPUT_STRING
  echo "You typed: $INPUT_STRING"
done

另一個比較常見的使用方式是while read f循環(huán)

while read f
  do
    case $f in
      hello)        echo English    ;;
        howdy)      echo American   ;;
        gday)       echo Australian ;;
        bonjour)    echo French ;;
        "guten tag")    echo German ;;
        *)      echo Unknown Language: $f
        ;;
    esac
  done < myfile

8.測試

在shell中,[代表測試,它本身是一個程序,就像ls、chmod一樣,而不是一個符號。所以[后面必須跟空格,否則shell會把[和后面的字符拼在一起解釋,導致問題。在Unix系統(tǒng)中,[是一個指向test程序的軟連接,也就是說:

if [$foo = "bar" ]

會被解釋為if test$foo = "bar" ],這也就是問題的所在了。可以看到,在shell中,使用=比較字符串,而對于整數(shù)則使用-eq。

1) if

if [ ... ]
then
  ...
else
  ...
fi

注意then必須另起一行。也可以加上;使其和if在同一行。在shell中;表示后面的語句是另一行語句,不過出于某種目的(比如說節(jié)約空間)所以寫在同一行。與其對應(yīng)的符號是\,表示下一行的語句應(yīng)該和本行語句視為同一行。下面的第二個shell運用了邏輯運算符的短路性質(zhì)。

if [ ... ]; then
  ...
fi
[ "$X" -nt "/etc/passwd" ] && \
      echo "X is a file which is newer than /etc/passwd"

也可以使用elif

if  [ something ]; then
 echo "Something"
 elif [ something_else ]; then
   echo "Something else"
 else
   echo "None of the above"
fi

9.預(yù)設(shè)變量

1) $0 $1 ... $9$#

  • $0表示當前程序(腳本)的名稱
  • $1 .. $9表示調(diào)用腳本時候傳入的前9個參數(shù)
  • 變量$@表示所有參數(shù) $*也有類似的作用但是它不保留空格和引號(通常情況下避免使用$*)
  • $#表示腳本調(diào)用時候傳入的參數(shù)個數(shù)
#!/bin/sh
echo "I was called with $# parameters"
echo "My name is $0"
echo "My first parameter is $1"
echo "My second parameter is $2"
echo "All parameters are $@"
$ ./var3.sh hello world earth
I was called with 3 parameters
My name is ./var3.sh
My first parameter is hello
My second parameter is world
All parameters are hello world earth

2) $?

這個變量包含上一個命令的退出值。在shell中,返回值0表示正常退出,所以可以通過test來判斷上一個命令執(zhí)行的時候有沒有執(zhí)行成功,增加程序的魯棒性。

#!/bin/sh
/usr/local/bin/my-command
if [ "$?" -ne "0" ]; then
  echo "Sorry, we had a problem there!"
fi

3)$$$!

  • $$變量表示當前的進程標識符,如果你的腳本允許存在多個實例同時運行的話,在創(chuàng)建文件的時候就可以在文件名上帶上這個進程標識符避免沖突:/temp/my_file.$$
  • $!變量表示最后運行的后臺進程標識符

10.花括號的高級用法

花括號除了用來保證變量的邊界外,還可以用來處理字符串undefined或者為null的情況(這兩者在shell里基本沒有區(qū)別),為其添加一個默認值,方法是在變量名后面加上:-

#!/bin/sh
echo "What is your name [ `whoami` ] \c"
read MY_NAME
echo "Hello ${MY_NAME:-`whoami`}"

上述腳本中的\c告訴echo命令不要換行。反引號中的內(nèi)容whoami被視為一個命令,命令在執(zhí)行之后的標準輸出會被替換為反引號所在的內(nèi)容。而whoami命令輸出的是當前登錄的用戶名稱,所以上述命令的作用是讓用戶鍵入自己的名稱,并且會顯示當前登錄的用戶名稱作為默認值,如果用戶直接點了回車沒有輸入內(nèi)容的話,則會輸出用戶的登錄名。

$ ./test.sh
What is your name [ melot ] abc
Hello abc
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,727評論 0 5
  • 1.Shell腳本 1.1 格式 首行 #!/bin/bash 指定解釋器 1.2 注釋 '#'開頭的行,'...
    keep_moving閱讀 1,299評論 4 45
  • 什么是運維 術(shù)語名詞 IDC--(Internet Data Center)互聯(lián)網(wǎng)數(shù)據(jù)中心,主要服務(wù)包括整機租用、...
    lyh165閱讀 2,881評論 0 19
  • .bat腳本基本命令語法 目錄 批處理的常見命令(未列舉的命令還比較多,請查閱幫助信息) 1、REM 和 :: 2...
    慶慶慶慶慶閱讀 8,541評論 1 19
  • 女兒提前幾天就在忙著準備夏令營的生活用品,今天早早就起床把東西收拾好了,今天沒有按照自己定下的計劃行動,沒有做作業(yè)...
    淺笑嫣然love閱讀 301評論 2 2

友情鏈接更多精彩內(nèi)容