變量
顯示所有環(huán)境變量:
$ env
# 或者
$ printenv
顯示某一個環(huán)境變量名:
$ echo $HOME
/root
# 或者
$ printenv HOME
/root
Bash 變量名區(qū)分大小寫,HOME和home是兩個不同的變量。
自定義變量是用戶在當(dāng)前 Shell 里面自己定義的變量,僅在當(dāng)前 Shell 可用。一旦退出當(dāng)前 Shell,該變量就不存在了。
顯示所有變量(包括環(huán)境變量和自定義變量),以及所有的 Bash 函數(shù):
$ set
一些變量賦值:
a=z # 變量 a 賦值為字符串 z
b="a string" # 變量值包含空格,就必須放在引號里面
c="a string and $b" # 變量值可以引用其他變量的值
#echo c --> "a string and a string"
由于$在 Bash 中有特殊含義,把它當(dāng)作美元符號使用時,一定要非常小心:
$ echo The total is $100.00
The total is 00.00
$ echo The total is \$100.00
The total is $100.00
讀取變量的時候,變量名也可以使用花括號{}包圍,比如$a也可以寫成${a}。這種寫法可以用于變量名與其他字符連用的情況:
$ a=foo
$ echo $a_file
$ echo ${a}_file
foo_file
如果變量的值本身也是變量,可以使用${!varname}的語法,讀取最終的值:
$ myvar=USER
$ echo ${myvar}
USER
$ echo ${!myvar}
ruanyf
如果變量值包含連續(xù)空格(或制表符和換行符),最好放在雙引號里面讀取:
$ a="1 2 3"
$ echo $a
1 2 3
$ echo "$a"
1 2 3
unset命令用來刪除一個變量:
unset NAME
不存在的 Bash 變量一律等于空字符串,所以即使unset命令刪除了變量,還是可以讀取這個變量,值為空字符串。
用戶創(chuàng)建的變量僅可用于當(dāng)前 Shell,子 Shell 默認(rèn)讀取不到父 Shell 定義的變量。為了把變量傳遞給子 Shell,需要使用export命令。這樣輸出的變量,對于子 Shell 來說就是環(huán)境變量。
export命令用來向子 Shell 輸出變量:
NAME=foo
export NAME
#或者
export NAME=value
舉例:
# 輸出變量 $foo
$ export foo=bar
# 新建子 Shell
$ bash
# 讀取 $foo
$ echo $foo
bar
# 修改繼承的變量
$ foo=baz
# 退出子 Shell
$ exit
# 讀取 $foo,子shell不影響父shell
$ echo $foo
bar
$?為上一個命令的退出碼,用來判斷上一個命令是否執(zhí)行成功。返回值是0,表示上一個命令執(zhí)行成功;如果不是零,表示上一個命令執(zhí)行失敗:
$ ls doesnotexist
ls: doesnotexist: No such file or directory
$ echo $?
1
$$為當(dāng)前 Shell 的進(jìn)程 ID:
$ echo $$
10662
$_為上一個命令的最后一個參數(shù):
$ grep dictionary /usr/share/dict/words
dictionary
$ echo $_
/usr/share/dict/words
$!為最近一個后臺執(zhí)行的異步命令的進(jìn)程 ID:
$ firefox &
[1] 11064
$ echo $!
11064
上面例子中,firefox是后臺運(yùn)行的命令,$!返回該命令的進(jìn)程 ID。
$0為當(dāng)前 Shell 的名稱(在命令行直接執(zhí)行時)或者腳本名(在腳本中執(zhí)行時):
$ echo $0
bash
$-為當(dāng)前 Shell 的啟動參數(shù):
$ echo $-
himBHs
$#表示腳本的參數(shù)數(shù)量,$@表示腳本的參數(shù)值。
如下表示如果變量varname存在且不為空,則返回它的值,否則返回word。比如${count:-0}表示變量count不存在時返回0:
${varname:-word}
如果變量varname存在且不為空,則返回它的值,否則將它設(shè)為word,并且返回word:
${varname:=word}
如果變量名存在且不為空,則返回word,否則返回空值。它的目的是測試變量是否存在:
${varname:+word}
如果變量varname存在且不為空,則返回它的值,否則打印出varname: message,并中斷腳本的執(zhí)行。它的目的是防止變量未定義,比如${count:?"undefined!"}表示變量count未定義時就中斷執(zhí)行,拋出錯誤,返回給定的報錯信息undefined!:
${varname:?message}
上面四種語法如果用在腳本中,變量名的部分可以用數(shù)字1到9,表示腳本的參數(shù):
#1表示腳本的第一個參數(shù)。如果該參數(shù)不存在,就退出腳本并報錯。
filename=${1:?"filename missing."}
declare命令可以聲明一些特殊類型的變量,為變量設(shè)置一些限制,比如聲明只讀類型的變量和整數(shù)類型的變量:
declare OPTION VARIABLE=value
-i參數(shù)聲明整數(shù)變量以后,可以直接進(jìn)行數(shù)學(xué)運(yùn)算:
$ val1=12 val2=5
$ declare -i result
$ result=val1*val2
$ echo $result
60
-x參數(shù)等同于export命令,可以輸出一個變量為子 Shell 的環(huán)境變量:
$ declare -x foo
# 等同于
$ export foo
-r參數(shù)可以聲明只讀變量,無法改變變量值,也不能unset變量:
$ declare -r bar=1
$ bar=2
bash: bar:只讀變量
$ echo $?
1
$ unset bar
bash: bar:只讀變量
$ echo $?
1
readonly命令等同于declare -r,用來聲明只讀變量,不能改變變量值,也不能unset變量:
$ readonly foo=1
$ foo=2
bash: foo:只讀變量
$ echo $?
1
let命令聲明變量時,可以直接執(zhí)行算術(shù)表達(dá)式:
$ let foo=1+2
$ echo $foo
3
let命令的參數(shù)表達(dá)式如果包含空格,就需要使用引號:
$ let "foo = 1 + 2"
let可以同時對多個變量賦值,賦值表達(dá)式之間使用空格分隔:
$ let "v1 = 1" "v2 = v1++" #先賦值,再自增
$ echo $v1,$v2
2,1
字符串操作
獲取字符串長度:
${#varname}
比如:
$ myPath=/home/cam/book/long.file.name
$ echo ${#myPath}
29
字符串提取子串的語法如下:
${varname:offset:length}
比如:
$ count=frogfootman
$ echo ${count:4:4}
foot
需要通過變量名傳入,不可直接傳入字符串:
# 報錯
$ echo ${"hello":2:3}
參數(shù)為負(fù)數(shù):
$ foo="This string is long."
$ echo ${foo: -5} #注意-5前面有空格,與${variable:-word}區(qū)分
long.
$ echo ${foo: -5:2}
lo
$ echo ${foo: -5:-2} #如果length為-2,表示要排除從字符串末尾開始的2個字符,所以返回lon
lon
字符串頭部匹配:
# 如果 pattern 匹配變量 variable 的開頭,
# 刪除最短匹配(非貪婪匹配)的部分,返回剩余部分
${variable#pattern}
# 如果 pattern 匹配變量 variable 的開頭,
# 刪除最長匹配(貪婪匹配)的部分,返回剩余部分
${variable##pattern}
比如:
$ myPath=/home/cam/book/long.file.name
$ echo ${myPath#/*/}
cam/book/long.file.name
$ echo ${myPath##/*/}
long.file.name
#如果匹配不成功,則返回原始字符串:
$ echo ${myPath#aaa}
/home/cam/book/long.file.name
如果要將頭部匹配的部分,替換成其他內(nèi)容,采用下面的寫法:
# 模式必須出現(xiàn)在字符串的開頭
${variable/#pattern/string}
# 示例
$ foo=JPG.JPG
$ echo ${foo/#JPG/jpg}
jpg.JPG
同樣的,字符串尾部匹配:
# 如果 pattern 匹配變量 variable 的結(jié)尾,
# 刪除最短匹配(非貪婪匹配)的部分,返回剩余部分
${variable%pattern}
# 如果 pattern 匹配變量 variable 的結(jié)尾,
# 刪除最長匹配(貪婪匹配)的部分,返回剩余部分
${variable%%pattern}
如果要將尾部匹配的部分,替換成其他內(nèi)容,采用下面的寫法:
# 模式必須出現(xiàn)在字符串的結(jié)尾
${variable/%pattern/string}
# 示例
$ foo=JPG.JPG
$ echo ${foo/%JPG/jpg}
JPG.jpg
任意位置匹配:
# 如果 pattern 匹配變量 variable 的一部分,
# 最長匹配(貪婪匹配)的那部分被 string 替換,但僅替換第一個匹配
${variable/pattern/string}
# 如果 pattern 匹配變量 variable 的一部分,
# 最長匹配(貪婪匹配)的那部分被 string 替換,所有匹配都替換
${variable//pattern/string}
比如:
$ path=/home/cam/foo/foo.name
$ echo ${path/foo/bar}
/home/cam/bar/foo.name
$ echo ${path//foo/bar}
/home/cam/bar/bar.name
配合通配符:
$ phone="555-456-1414"
$ echo ${phone/5?4/-}
55-56-1414
下面的語法可以改變變量的大小寫:
# 轉(zhuǎn)為大寫
${varname^^}
# 轉(zhuǎn)為小寫
${varname,,}
比如:
$ foo=heLLo
$ echo ${foo^^}
HELLO
$ echo ${foo,,}
hello
((...))語法可以進(jìn)行整數(shù)的算術(shù)運(yùn)算:
$ ((foo = 5 + 5))
$ echo $foo
10
這個語法不返回值,命令執(zhí)行的結(jié)果根據(jù)算術(shù)運(yùn)算的結(jié)果而定。只要算術(shù)結(jié)果不是0,命令就算執(zhí)行成功:
$ (( 3 + 2 ))
$ echo $?
0
$ (( 3 - 3 ))
$ echo $?
1
如果要讀取算術(shù)運(yùn)算的結(jié)果,需要在((...))前面加上美元符號$((...)),使其變成算術(shù)表達(dá)式,返回算術(shù)運(yùn)算的值:
$ echo $((2 + 2))
4
這個語法只能計算整數(shù),否則會報錯:
# 報錯
$ echo $((1.5 + 1))
bash: 語法錯誤
$((...))的圓括號之中,不需要在變量名之前加上$,不過加上也不報錯:
$ number=2
$ echo $(($number + 1))
3
如果在$((...))里面使用字符串,Bash 會認(rèn)為那是一個變量名。如果不存在同名變量,Bash 就會將其作為空值,因此不會報錯:
$ echo $(( "hello" + 2))
2
$ echo $(( "hello" * 2))
0
$ hello=1
$ echo $(("hello"+1))
2
可以進(jìn)行動態(tài)替換:
$ foo=hello
$ hello=3
$ echo $(( foo + 2 ))
5
$[...]是以前的語法,也可以做整數(shù)運(yùn)算,不建議使用:
$ echo $[2+2]
4
bash中的進(jìn)制:
number:沒有任何特殊表示法的數(shù)字是十進(jìn)制數(shù)(以10為底)。
0number:八進(jìn)制數(shù)。
0xnumber:十六進(jìn)制數(shù)。
base#number:base進(jìn)制的數(shù)。
比如:
$ echo $((0xff))
255
$ echo $((2#11111111))
255
位運(yùn)算:
<<:位左移運(yùn)算,把一個數(shù)字的所有位向左移動指定的位。
>>:位右移運(yùn)算,把一個數(shù)字的所有位向右移動指定的位。
&:位的“與”運(yùn)算,對兩個數(shù)字的所有位執(zhí)行一個AND操作。
|:位的“或”運(yùn)算,對兩個數(shù)字的所有位執(zhí)行一個OR操作。
~:位的“否”運(yùn)算,對一個數(shù)字的所有位取反。
^:位的異或運(yùn)算(exclusive or),對兩個數(shù)字的所有位執(zhí)行一個異或操作。
比如:
$ echo $((16>>2))
4
邏輯運(yùn)算:
$((...))支持以下邏輯運(yùn)算:
<:小于
>:大于
<=:小于或相等
>=:大于或相等
==:相等
!=:不相等
&&:邏輯與
||:邏輯或
!:邏輯否
expr1?expr2:expr3:三元條件運(yùn)算符。若表達(dá)式expr1的計算結(jié)果為非零值(算術(shù)真),則執(zhí)行表達(dá)式expr2,否則執(zhí)行表達(dá)式expr3。
比如:
$ echo $(( (3 > 2) || (4 <= 1) ))
1
$ a=0
$ echo $((a<1 ? 1 : 0))
1
$ echo $((a>1 ? 1 : 0))
0
((...))可以執(zhí)行賦值運(yùn)算:
$ echo $((a=1))
1
$ echo $a
1
如果在表達(dá)式內(nèi)部賦值,可以放在圓括號中,否則會報錯:
$ a=0
$ echo $(( a<1 ? (a+=1) : (a-=1) ))
1
逗號,在$((...))內(nèi)部是求值運(yùn)算符,執(zhí)行前后兩個表達(dá)式,并返回后一個表達(dá)式的值:
$ echo $((foo = 1 + 2, 3 * 4)) #兩個表達(dá)式都會執(zhí)行,然后返回后一個表達(dá)式的值12
12
$ echo $foo
3
expr命令支持算術(shù)運(yùn)算,可以不使用((...))語法,也只支持整數(shù)運(yùn)算:
$ expr 3 + 2
5
$ foo=3
$ expr $foo + 2
5
let命令用于將算術(shù)運(yùn)算的結(jié)果,賦予一個變量:
$ let x=2+3
$ echo $x
5
注意,x=2+3這個式子里面不能有空格,否則會報錯。
bash會保留歷史操作在文件中,環(huán)境變量HISTFILE總是指向這個文件。
$ echo $HISTFILE
/home/me/.bash_history
history命令會輸出這個文件的全部內(nèi)容。用戶可以看到最近執(zhí)行過的所有命令,每條命令之前都有行號。越近的命令,排在越后面:
$ history
...
498 echo Goodbye
499 ls ~
500 cd
輸入命令時,按下Ctrl + r快捷鍵,就可以搜索操作歷史,選擇以前執(zhí)行過的命令。這時鍵入命令的開頭部分,Shell 就會自動在歷史文件中,查詢并顯示最近一條匹配的結(jié)果,這時按下回車鍵,就會執(zhí)行那條命令。
!e表示找出操作歷史之中,最近的那一條以e開頭的命令并執(zhí)行。Bash 會先輸出那一條命令echo Goodbye,然后直接執(zhí)行:
$ echo Hello World
Hello World
$ echo Goodbye
Goodbye
$ !e
echo Goodbye
Goodbye
由于!string語法會擴(kuò)展成以前執(zhí)行過的命令,所以含有!的字符串放在雙引號里面,必須非常小心:
$ echo "hello!" #雙引號中!后無字符
hello!
$ echo "I say:\"hello!\"" #雙引號中!后有字符
bash: !\: event not found
#需要對!轉(zhuǎn)義:
$ echo "I say:\"hello\!\""
I say:"hello\!"
上面的命令會報錯,原因是感嘆號后面是一個反斜杠,Bash 會嘗試尋找,以前是否執(zhí)行過反斜杠開頭的命令,一旦找不到就會報錯。解決方法就是在感嘆號前面,也加上反斜杠。
在history中顯示時間戳:
$ export HISTTIMEFORMAT='%F %T '
$ history
1 2013-06-09 10:40:12 cat /etc/issue
2 2013-06-09 10:40:12 clear
上面代碼中,%F相當(dāng)于%Y - %m - %d,%T相當(dāng)于%H : %M : %S。
環(huán)境變量HISTSIZE設(shè)置保存歷史操作的數(shù)量:
$ export HISTSIZE=10000
上面命令設(shè)置保存過去10000條操作歷史。
如果不希望保存本次操作的歷史,可以設(shè)置HISTSIZE等于0:
export HISTSIZE=0
如果HISTSIZE=0寫入用戶主目錄的~/.bashrc文件,那么就不會保留該用戶的操作歷史。如果寫入/etc/profile,整個系統(tǒng)都不會保留操作歷史。
環(huán)境變量HISTIGNORE可以設(shè)置哪些命令不寫入操作歷史:
export HISTIGNORE='pwd:ls:exit'
上面示例設(shè)置,pwd、ls、exit這三個命令不寫入操作歷史。
操作歷史的每一條記錄都有編號。知道了命令的編號以后,可以用感嘆號 + 編號執(zhí)行該命令。如果想要執(zhí)行.bash_history里面的第8條命令,可以像下面這樣操作:
$ !8
history命令的-c參數(shù)可以清除操作歷史:
$ history -c
cd -命令可以返回前一次的目錄:
# 當(dāng)前目錄是 /path/to/foo
$ cd bar
# 重新回到 /path/to/foo
$ cd -
如果希望記憶多重目錄,可以使用pushd命令和popd命令。它們用來操作目錄堆棧:
pushd命令的用法類似cd命令,可以進(jìn)入指定的目錄,并將該目錄放入堆棧:
$ pushd dirname
第一次使用pushd命令時,會將當(dāng)前目錄先放入堆棧,然后將所要進(jìn)入的目錄也放入堆棧,位置在前一個記錄的上方。以后每次使用pushd命令,都會將所要進(jìn)入的目錄,放在堆棧的頂部。
popd命令不帶有參數(shù)時,會移除堆棧的頂部記錄,并進(jìn)入新的棧頂目錄(即原來的第二條目錄)。
比如:
# 當(dāng)前處在主目錄,堆棧為空
$ pwd
/home/me
# 進(jìn)入 /home/me/foo
# 當(dāng)前堆棧為 /home/me/foo /home/me
$ pushd ~/foo
# 進(jìn)入 /etc
# 當(dāng)前堆棧為 /etc /home/me/foo /home/me
$ pushd /etc
# 進(jìn)入 /home/me/foo
# 當(dāng)前堆棧為 /home/me/foo /home/me
$ popd
# 進(jìn)入 /home/me
# 當(dāng)前堆棧為 /home/me
$ popd
# 目錄不變,當(dāng)前堆棧為空
$ popd
這兩個命令的參數(shù)如下:
-n的參數(shù)表示僅刪除堆棧頂部的記錄,不改變目錄,執(zhí)行完成后還停留在當(dāng)前目錄:
$ popd -n
這兩個命令還可以接受一個整數(shù)作為參數(shù),該整數(shù)表示堆棧中指定位置的記錄(從0開始)。pushd命令會把這條記錄移動到棧頂,同時切換到該目錄;popd則從堆棧中刪除這條記錄,不會切換目錄:
# 將從棧頂算起的3號目錄(從0開始)移動到棧頂,同時切換到該目錄
$ pushd +3
# 將從棧底算起的3號目錄(從0開始)移動到棧頂,同時切換到該目錄
$ pushd -3
# 刪除從棧頂算起的3號目錄(從0開始),不改變當(dāng)前目錄
$ popd +3
# 刪除從棧底算起的3號目錄(從0開始),不改變當(dāng)前目錄
$ popd -3
dirs命令可以顯示目錄堆棧的內(nèi)容,一般用來查看pushd和popd操作后的結(jié)果:
$ dirs
~/foo/bar ~/foo ~
棧頂(最晚入棧的目錄)在最左邊,棧底(最早入棧的目錄)在最右邊。
dirs -c:清空目錄棧。
腳本一般以Shebang行開頭:
#!/bin/sh
# 或者
#!/bin/bash
如果bash解釋器不在/bin目錄,也可以這么寫:
#!/usr/bin/env bash
解釋:env命令會返回環(huán)境變量。當(dāng)執(zhí)行 env python 時,它其實(shí)會去 env | grep PATH 里(也就是 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin)這幾個路徑里去依次查找名為 python 的可執(zhí)行文件。
腳本入門
如果將腳本放在環(huán)境變量$PATH指定的目錄中,就不需要指定路徑了。因?yàn)?Bash 會自動到這些目錄中,尋找是否存在同名的可執(zhí)行文件。
建議在主目錄新建一個~/bin子目錄,專門存放可執(zhí)行腳本,然后把~/bin加入$PATH:
export PATH=$PATH:~/bin
可以將這一行加到~/.bashrc文件里面,然后重新加載一次.bashrc,這個配置就可以生效了:
$ source ~/.bashrc
以后不管在什么目錄,直接輸入腳本文件名,腳本就會執(zhí)行:
$ script.sh
Bash 腳本中,#表示注釋。
調(diào)用腳本可以帶參數(shù):
$ script.sh word1 word2 word3
腳本文件內(nèi)部,可以使用特殊變量,引用這些參數(shù):
$0:腳本文件名,即script.sh。
$1~$9:對應(yīng)腳本的第一個參數(shù)到第九個參數(shù)。
$#:參數(shù)的總數(shù)。
$@:全部的參數(shù),參數(shù)之間使用空格分隔。
$*:全部的參數(shù),參數(shù)之間使用變量$IFS值的第一個字符分隔,默認(rèn)為空格,但是可以自定義。
如果腳本的參數(shù)多于9個,那么第10個參數(shù)可以用${10}的形式引用,以此類推。
比如script.sh如下:
#!/bin/bash
# script.sh
echo "全部參數(shù):" $@
echo "命令行參數(shù)數(shù)量:" $#
echo '$0 = ' $0
echo '$1 = ' $1
echo '$2 = ' $2
echo '$3 = ' $3
運(yùn)行結(jié)果如下:
$ ./script.sh a b c
全部參數(shù):a b c
命令行參數(shù)數(shù)量:3
$0 = script.sh
$1 = a
$2 = b
$3 = c
如果多個參數(shù)放在雙引號里面,視為一個參數(shù)。
$ ./script.sh "a b"
上面例子中,Bash 會認(rèn)為"a b"是一個參數(shù),$1會返回a b。注意,返回時不包括雙引號。
shift命令:
shift命令可以改變腳本參數(shù),每次執(zhí)行都會移除腳本當(dāng)前的第一個參數(shù)($1),使得后面的參數(shù)向前一位,即$2變成$1、$3變成$2、$4變成$3,以此類推:
#!/bin/bash
#while循環(huán)結(jié)合shift命令,也可以讀取每一個參數(shù)
echo "一共輸入了 $# 個參數(shù)"
while [ "$1" != "" ]; do
echo "剩下 $# 個參數(shù)"
echo "參數(shù):$1"
shift
done
shift命令的默認(rèn)參數(shù)為1,如上。也可以shift 3,表示移除前三個參數(shù),原來的$4變成$1。
getopts命令
getopts命令用在腳本內(nèi)部,用于取出腳本所有的帶有前置連詞線-的參數(shù)(配置項參數(shù)):
getopts optstring name
第一個參數(shù)optstring是字符串,給出腳本所有的連詞線參數(shù)。比如,某個腳本可以有三個配置項參數(shù)-l、-h、-a,其中只有-a可以帶有參數(shù)值,而-l和-h是開關(guān)參數(shù),那么getopts的第一個參數(shù)寫成lha:,順序不重要。注意,a后面有一個冒號,表示該參數(shù)帶有參數(shù)值。getopts的第二個參數(shù)name是一個變量名,用來保存當(dāng)前取到的配置項參數(shù),即l、h或a。
比如使用getopts命令配合while循環(huán)處理參數(shù):
while getopts 'lha:' OPTION; do
case "$OPTION" in
l)
echo "linuxconfig"
;;
h)
echo "h stands for h"
;;
a)
avalue="$OPTARG" #如果某個連詞線參數(shù)帶有參數(shù)值,比如-a foo,那么處理a參數(shù)的時候,環(huán)境變量$OPTARG保存的就是參數(shù)值。
echo "The value provided is $OPTARG"
;;
?) #如果用戶輸入了沒有指定的參數(shù)(比如-x),那么OPTION等于?。
echo "script usage: $(basename $0) [-l] [-h] [-a somevalue]" >&2
exit 1
;;
esac
done
shift "$(($OPTIND - 1))" #變量$OPTIND在getopts開始執(zhí)行前是1,然后每次執(zhí)行就會加1。
basename命令用于去掉文件名的目錄和后綴。
變量$OPTIND在getopts開始執(zhí)行前是1,然后每次執(zhí)行就會加1。等到退出while循環(huán),就意味著連詞線參數(shù)全部處理完畢。這時,$OPTIND - 1就是已經(jīng)處理的連詞線參數(shù)個數(shù),使用shift命令將這些參數(shù)移除,保證后面的代碼可以用$1、$2等處理命令的主參數(shù)。
-和--開頭的參數(shù),會被 Bash 當(dāng)作配置項解釋。那如果需要創(chuàng)建文件名為--test,需使用配置項參數(shù)終止符--,表示后面的參數(shù)都是實(shí)體參數(shù):
$ touch -- --test
比如:
$ myPath="-l"
$ ls -- $myPath
ls: 無法訪問'-l': 沒有那個文件或目錄
如果想在文件里面搜索--hello,這時也要使用參數(shù)終止符--:
$ grep -- "--hello" example.txt
如果不用參數(shù)終止符,grep命令就會把--hello當(dāng)作配置項參數(shù),從而報錯。
exit命令用于終止當(dāng)前腳本的執(zhí)行,并向 Shell 返回一個退出值。exit命令后面可以跟參數(shù),該參數(shù)就是退出狀態(tài):
# 退出值為0(成功)
$ exit 0
# 退出值為1(失?。?$ exit 1
比如:
if [ $(id -u) != "0" ]; then
echo "根用戶才能執(zhí)行當(dāng)前腳本"
exit 1
fi
id -u命令返回用戶的 ID,一旦用戶的 ID 不等于0(根用戶的 ID),腳本就會退出,并且退出碼為1,表示運(yùn)行失敗。
命令執(zhí)行結(jié)束后,會有一個返回值。0表示執(zhí)行成功,非0(通常是1)表示執(zhí)行失敗。環(huán)境變量$?可以讀取前一個命令的返回值:
cd /path/to/somewhere
if [ "$?" = "0" ]; then
rm *
else
echo "無法切換目錄!" 1>&2
exit 1
fi
也可以使用if直接判斷命令執(zhí)行結(jié)果:
if cd /path/to/somewhere; then
rm *
else
echo "Could not change directory! Aborting." 1>&2
exit 1
fi
正常的執(zhí)行腳本文件,是類似于bash *.sh,其實(shí)是調(diào)用子shell。而source命令不會調(diào)用子shell,所以常用于加載配置文件:
比如:
#!/bin/bash
# test.sh
echo $foo
使用不同方式調(diào)用:
# 當(dāng)前 Shell 新建一個變量 foo
$ foo=1
# 打印輸出 1
$ source test.sh
1
# 打印輸出空字符串 #這一步如果想要輸出1則需要在之前export foo=1
$ bash test.sh
source命令的另一個用途,是在腳本內(nèi)部加載外部庫:
#!/bin/bash
source ./lib.sh
function_from_lib
source有一個簡寫形式,可以使用一個點(diǎn).來表示:
$ . .bashrc
alias命令用來為一個命令指定別名,這樣更便于記憶:
alias NAME=DEFINITION
比如:
alias search=grep
alias也可以用來為長命令指定一個更短的別名。下面是通過別名定義一個today的命令:
$ alias today='date +"%A, %B %-d, %Y"'
$ today
星期一, 一月 6, 2020
alias定義的別名也可以接受參數(shù),參數(shù)會直接傳入原始命令(其實(shí)就是個替換的過程):
$ alias echo='echo It says: '
$ echo hello world
It says: hello world
直接調(diào)用alias命令,可以顯示所有別名:
$ alias
unalias命令可以解除別名:
$ unalias lt