shell相關(guān)2

變量

顯示所有環(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è)置,pwdls、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

參考:https://wangdoc.com/bash/script.html

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

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

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