1. 程式人生 > >Linux shell 自動安裝總結

Linux shell 自動安裝總結

本文主要針對web專案自動安裝shell指令碼中常用linux命令總結如下:

1. 將一條命令的執行結果賦值給一個變數:

#獲取執行指令碼的當前路徑
zit_script_path=$(cd "$(dirname "$0")" && pwd)
#獲取執行指令碼的當前路徑
zit_script_path=$(cd "$(dirname "$0")";pwd)

1.1 Linux 中常用的轉義字元

  • 反斜槓(\) :  使反斜槓後面的一個變數變為單純的字串;
  • 單引號(''):  轉義其中所有的變數為單純的字串;
  • 雙引號("")
    : 保留其中的變數屬性,不進行轉義處理;
  • 反引號(``): 把其中的命令執行後返回結果。等價於 $();

1.2 Linux 下多個命令連續執行

  • 分隔符(;): 無論前面的命令執行成功與否,都會執行後一條命令;
  • 分隔符(&&): 只有前面的命令執行成功了,才會執行後一條命令;相當於 短路與
zit_path=`cd /usr/hello && pwd`
# hello不存在 zit_path等於空
  • 分隔符(||): 只有當前面的命令執行失敗了,才會執行後面的命令;相當於 短路或

1.3 Linux中傳遞給指令碼shell的引數表示

./start.sh a b c

$# 是傳給指令碼的引數個數 : 3

$0 是指令碼本身的名字 : start.sh

$1 是傳遞給該shell指令碼的第一個引數 : a

$2 是傳遞給該shell指令碼的第二個引數 : b

[email protected] 是傳給指令碼的所有引數的列表 : a b c
for key in "[email protected]"
# for key in [email protected] 
do
    echo $key
done
有無雙引號輸出結果相同: 
a
b 
c
$* 是以一個單字串顯示所有向指令碼傳遞的引數,與位置變數不同,引數可超過9個 :    

for key2 in $*
do 
    echo $key2
done
輸出結果:
a
b
c

for key2 in "$*"
do
    echo $key2
done
帶引號的輸出結果:
a b c 
$$ 是指令碼執行的當前程序ID號 : 3324 $? 是顯示最後命令的退出狀態,0表示沒有錯誤,其他表示有錯誤

1.4 Linux 的 dirname 和 basename

dirname -[選項] 名稱
 輸出名稱中的目錄部分,如果名稱僅僅只是一個檔名,則輸出".",表示當前目錄
dirname /usr/install  # install 為一個目錄(資料夾)
    輸出:/usr 
dirname /usr/install/install.sh 
    輸出:/usr/install
dirname install.sh
    輸出. #.表示當前目錄 無論上面的檔案是否存在或者是否在當前目錄
basename -[選項] 名稱
   -a : 移除多個名稱的目錄
   -s : 移除相應的字尾名稱
  表示移除名稱的目錄,僅保留檔名 
basename -a dir1/str dir2/str  
    輸出: dir1
          dir2 
basename -a dir1/str dir2/str
    輸出: dir1
basename -s .jpg dir1/str.jpg
    輸出: str
basename --suffix=.jpg dir1/str.jpg
    輸出: str

2. Linux shell 讀取配置檔案中的變數

2.1 source命令的巧妙用法

source filename 或者 . filename 通常用於重新執行剛修改的初始化檔案,使之立即生效,而不必登出並重新登入。

例如,當我們修改了/etc/profile檔案,並想讓它立刻生效,而不用重新登入,就可以使用source命令,

source /etc/profile

source filename 只是簡單地讀取腳本里面的語句依次在當前shell裡面執行,沒有建立新的子shell。那麼腳本里面所有新建、改變變數的語句都會儲存在當前shell裡面。因為不會建立新的子shell,變數的值都可以直接取到.

配置檔案 db.ini:

db_username=root
db_port=3306
db_password=xxx

readConf.sh:

#!/bin/bash
source ./db.ini
# 會依次讀取db.ini檔案中的語句在當前shell中執行,而db_username=root剛好是linux中定義變數的方式,所有db_username這個變數
#會在當前的shell中生效,因此我們可以在這個shell檔案中直接使用這個變數
dbUsername=${db_username}
dbPort=${db_port}
dbPassword=${db_password}
echo $dbUsername

sh filepath或者./filepath: 會重新建立一個子shell,在子shell中執行腳本里面的語句,該子shell繼承父shell的環境變數,但子shell是新建的,其改變的變數不會被帶回父shell,除非使用export。

2.2 awk命令

參考文件:linux awk命令詳解

簡單來說awk就是把檔案逐行的讀入,以 空格 為預設分隔符將每行切片,切開的部分再進行各種分析處理。

使用方法

awk -F'域分隔符' 'pattern + action' filenames
    -F後面跟域分割符號,預設是依空格進行分割的例如: awk -F: #依“:”進行行的域分割
    pattern: 要查詢的內容,支援正則表示式,將要查詢的內容用"/"進行包圍;
        awk -F':' '/root/{print $6}' /etc/passwd 
        #查詢到有root關鍵詞的行,並輸入第6個域的內容
    action:執行的命令

呼叫awk

有三種方式呼叫awk

1.命令列方式
awk [-F  field-separator]  '/pattern/{commands}'  input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可選的。 input-file(s) 是待處理的檔案。
在awk中,檔案的每一行中,由域分隔符分開的每一項稱為一個域。通常,在不指名-F域分隔符的情況下,預設的域分隔符是空格。

2.shell指令碼方式
將所有的awk命令插入一個檔案,並使awk程式可執行,然後awk命令直譯器作為指令碼的首行,一遍通過鍵入指令碼名稱來呼叫。
相當於shell指令碼首行的:#!/bin/sh
可以換成:#!/bin/awk

3.將所有的awk命令插入一個單獨檔案,然後呼叫:
awk -f awk-script-file input-file(s)
其中,-f選項載入awk-script-file中的awk指令碼,input-file(s)跟上面的是一樣的。

awk內建變數

awk有許多內建變數用來設定環境資訊,這些變數可以被改變,下面給出了最常用的一些變數。

ARGC               命令列引數個數
ARGV               命令列引數排列
ENVIRON            支援佇列中系統環境變數的使用
FILENAME           awk瀏覽的檔名
FNR                瀏覽檔案的記錄數
FS                 設定輸入域分隔符,等價於命令列 -F選項
NF                 瀏覽記錄的域的個數
NR                 已讀的記錄數
OFS                輸出域分隔符
ORS                輸出記錄分隔符
RS                 控制記錄分隔符

 此外,$0變數是指整條記錄。$1表示當前行的第一個域,$2表示當前行的第二個域,......以此類推。

 統計/etc/passwd:檔名,每行的行號,每行的列數,對應的完整行內容:

#awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/sh
filename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh
filename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh

2.3 sed命令

sed 把當前處理的行儲存在臨時緩衝區中,稱為“模式空間”(pattern space),接著用sed命令處理緩衝區中的內容,處理完成後,把緩衝區的內容送往螢幕。接著處理下一行,這樣不斷重複,直到檔案末尾。檔案內容並沒有 改變,除非你使用重定向儲存輸出。

參考文件:

命令格式

sed [options] 'command' file(s)
sed [options] -f scriptfile file(s)
-e<script>或--expression=<script>:以選項中的指定的script來處理輸入的文字檔案;
-f<script檔案>或--file=<script檔案>:以選項中指定的script檔案來處理輸入的文字檔案;

sed替換標記

g 表示行內全面替換。  
p 表示列印行。  
w 表示把行寫入一個檔案。  
x 表示互換模板塊中的文字和緩衝區中的文字。  
y 表示把一個字元翻譯為另外的字元(但是不用於正則表示式)
\1 子串匹配標記
& 已匹配字串標記

sed元字符集

^ 匹配行開始,如:/^sed/匹配所有以sed開頭的行。
$ 匹配行結束,如:/sed$/匹配所有以sed結尾的行。
. 匹配一個非換行符的任意字元,如:/s.d/匹配s後接一個任意字元,最後是d。
* 匹配0個或多個字元,如:/*sed/匹配所有模板是一個或多個空格後緊跟sed的行。
[] 匹配一個指定範圍內的字元,如/[ss]ed/匹配sed和Sed。  
[^] 匹配一個不在指定範圍內的字元,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一個字母開頭,緊跟ed的行。
\(..\) 匹配子串,儲存匹配的字元,如s/\(love\)able/\1rs,loveable被替換成lovers。
& 儲存搜尋字元用來替換其他字元,如s/love/**&**/,love這成**love**。
\< 匹配單詞的開始,如:/\<love/匹配包含以love開頭的單詞的行。
\> 匹配單詞的結束,如/love\>/匹配包含以love結尾的單詞的行。
x\{m\} 重複字元x,m次,如:/0\{5\}/匹配包含5個0的行。
x\{m,\} 重複字元x,至少m次,如:/0\{5,\}/匹配至少有5個0的行。
x\{m,n\} 重複字元x,至少m次,不多於n次,如:/0\{5,10\}/匹配5~10個0的行。

sed用法例項

替換文字中的字串:

sed 's/book/books/' file

-n選項p命令一起使用表示只打印那些發生替換的行:

sed -n 's/test/TEST/p' file

直接編輯檔案選項-i使用字尾 /g 標記會替換每一行中的所有匹配:會匹配file檔案中每一行中所有的book替換為books:

sed -i 's/book/books/g' file

以上命令中字元 / 在sed中作為定界符使用,也可以使用任意的定界符:

sed 's#test#TEXT#g' file

-d: 刪除操作

刪除文中的空白行

sed 's/^$/d' file
& 對應於之前所匹配到的單詞:
sed 's/^192.168.0.1/&localhost/' file
192.168.0.1localhost
樣式匹配子串標識位 \(.....\) -> \1

\(..\) 用於匹配子串,對於匹配到的第一個子串就標記為 \1,依此類推匹配到的第二個結果就是 \2,例如:

echo aaa BBB | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
BBB aaa
sed表示式可以使用單引號來引用,但是如果表示式內部包含變數字串,就需要使用雙引號。

, 逗號用於選定行的範圍

sed -n '/test/,/check/p' file 

所有在模板test和check所確定的範圍內的行都被列印:

3. 判斷一個目錄是否存在,如果不存在就自動建立,並把安裝檔案拷入

#判斷安裝目錄是否存在
if [ ! -d ${installDir} ]; then
	mkdir -p ${installDir}
	# 複製所有檔案到安裝目錄
	cp -a -f ./* ${installDir}
	cd ${installDir}
else
	cp -a -f ./* ${installDir}
	cd ${installDir}
fi

3.1 Linux 判斷使用者的引數

3.1.1 檔案測試邏輯語句

檔案測試即使用指定條件來判斷檔案是否存在或者許可權是否滿足等情況的運算子,

  • -d : 測試檔案是否為一個目錄型別
  • -e : 測試檔案是否存在
  • -f : 判斷是否為一個一般檔案
  • -r : 測試當前使用者是否有許可權讀寫
  • -w : 測試當前使用者是否有權寫入
  • -x : 測試當前使用者是否有權執行

其中,對於目錄檔案來說,可讀:表示能夠讀取目錄內的檔案列表; 可寫: 表示能夠在目錄內新增、刪除、重新命名檔案;可執行:表示可以進入這個目錄。

常配合目錄建立 刪除, 複製,等操作

mkdir 命令重要引數:

- m :  為目錄指定許可權;

# 預設創建出來的目錄為-drwxr-xr-x
mkdir -m 775 dir1 

- p :  遞迴建立;在建立目錄過程中,如果那些目錄不存在,就建立這些目錄

mkdir -p totalDir/{dir1,dir2,dir3/{dir3-1,dir3-2,dir3-3}}

cp 命令重要引數 :

  • -a:此選項通常在複製目錄時使用,它保留連結、檔案屬性,並複製目錄下的所有內容。其作用等於dpR引數組合。
  • -d:複製時保留連結。
  • -f:覆蓋已經存在的目標檔案而不給出提示。
  • -i:與-f選項相反,在覆蓋目標檔案之前給出提示,要求使用者確認是否覆蓋,回答"y"時目標檔案將被覆蓋。
  • -p:除複製檔案的內容外,還把修改時間和訪問許可權也複製到新檔案中。
  • -r:若給出的原始檔是一個目錄檔案,此時將複製該目錄下所有的子目錄和檔案。
  • -l:不復制檔案,只是生成連結檔案
#將當前目錄下面的所有檔案複製到目標目錄下,並且保持當前目錄下檔案的屬性 -a =-d -p -r ; -f 覆蓋已存在的檔案不進行提示
cp -a -f ./* ${installDir}

rm 命令重要引數:

可以刪除一個目錄中的一個或多個檔案或目錄,也可以將某個目錄及其下屬的所有檔案及其子目錄均刪除掉。對於連結檔案,只是刪除整個連結檔案,而原有檔案保持不變。

  • - f : 強制刪除一個檔案或目錄,當這個目錄不空時,無法刪除
  • - r : 遞迴處理,將指定目錄下的所有檔案與子目錄一併刪除
  • - i : 詢問使用者是否刪除
# 強制遞迴刪除totalDir資料夾
rm -r -f totalDir

3.1.2 邏輯測試語句對測試結果進行邏輯分析

“與”(&&):表示前面的命令執行成功後,才會執行它後面的命令,

# 判斷當前目錄是否存在,存在就刪除
[ -d ./totalDIR ] && rm -r -f ./totalDIR

“或”(||):表示當前面的命令執行失敗後才會執行它後面的命令,

[ $USER != root ] || echo you must be root user!!

“非”(!):把條件測試中的判斷結果取相反值,

if [ ! -d ${installDir} ]; then
	mkdir -p ${installDir}
fi

3.1.3 整數比較運輸符:只是對數字的操作

  • -eq : 是否等於
  • -ne : 是否不等於
  • -gt : 是否大於
  • -lt : 是否小於
  • -le : 是否等於或小於
  • -ge : 是否大於或等於
FREE_MEN=free -m | grep Mem | awk '{print $4}'
[ FREE_MEN -lt 1024 ] && echo "Insufficient Memory"

3.1.4 字串比較語句

  •  = : 比較兩個字串是否相等
  • !=:比較兩個字串的內容是否不同
  • -z : 判斷字串內容是否為空
[ $LANG != "en.US" ]

4. 將查到到符合條件的檔案放入一個數組,然後遍歷這個陣列對檔案進行一一操作

#根據資料庫型別刪除相應的資料庫驅動jar包
if [ "$dbType" == "MSSQL2008" ]; then
        # 宣告一個數組
        declare -a MSQL2008_ARR
	MSSQL2008_ARR=$(find ./server -name sqljdbc2005.jar)
	if [ ${#MSSQL2008_ARR[@]} -gt 0 ]; then
		for i in ${MSSQL2008_ARR[@]}; do
			rm -f $i
		done
	fi

4.1 對陣列的操作;

4.1.1 宣告一個數組:

陣列的腳標從0開始;

直接賦值:

array[0]=”Zero” array[1]=”One” array[2]=”Two”

declare宣告:

declare -a arrayName  #arrayName被當作陣列名

小括號加空格定義陣列:

arrayName=( value1 value2 value3 ... )

雙引號加空格定義陣列:

array=”Zero One Two”

混合法:

array=([0]=”Zero” [1]=”One” [2]=”Two”)

4.1.2 陣列操作

 獲取陣列長度和遍歷陣列:

    
# 取得陣列元素的個數
length=${#array_name[@]}
    # 遍歷陣列
    for data in ${array_name[@]}  
    do  
        echo ${data}  
    done      
# 或者
length=${#array_name[*]}
    # 遍歷陣列
    for(( i=0; i<${length}; i++ )) 
    do 
        echo ${array[i]}; 
    done
# 取得陣列 單個元素 的長度
lengthn=${#array_name[n]}

陣列賦值和刪除陣列

a=(1 2 3 4 5 6 7 8)
a[1]=100
echo ${a[*]} # 1 100 2 3 4 5 6 7 8
a[11]=200
${a[*]} # 1 100 2 3 4 5 6 7 8 200 
如果下標不存在就直接新增一個新的元素在末尾

#刪除元素
unset array_name #刪除陣列
unset array_name[i] #刪除第i個腳標的元素

陣列切片與替換

a=(1 2 3 4 5 6 7 8)
echo ${a[@]:0:3} #[ )
    1 2 3
c=(${a[@]:1:4})
echo ${c[*]} 
    2 3 4 5
# 陣列元素替換 
a=(1 2 3 4 5 6 7 8)
echo ${a[@]/3/100} # 將陣列中的3 替換成100
# 輸出:1 2 100 4 5 6 7 8
echo ${a[*]}
# 輸出:1 2 3 4 5 6 7 8 #原陣列的值並沒有發生變化

a=(${a[@]/3/100})
echo ${a[@]}
# 輸出:1 2 100 4 5 6 7 8 #從新賦值給一個新的陣列 替換掉源陣列的值


4.2 cat file 返回一個數組

vim user.txt
    zhangsan
    lisi
    wangwu
    zhaoliu
# cat 出來的內容直接作為一個數組
NAME_ARR=$(cat ./user.txt)
for user in NAME_ARR
do
    echo $NAME_ARR
done

4.3 find 命令

find path -iname fileName*

#查詢當前目錄下所有dir開頭的指令碼檔案(忽略大小寫)
find . -iname dir*.sh

4.4 grep命令

參考文件 Linux grep 命令詳解

grep [-cinv] [--color=auto] '搜尋字串' filename1 filename2 

要搜尋的字元中中可以使用正則表示式 用單引號包裹 
filename 是檔名,不能為目錄

選項與引數:
-c :計算找到 '搜尋字串' 的次數
-i :忽略大小寫的不同,所以大小寫視為相同
-n :順便輸出行號
-v :反向選擇,亦即顯示出沒有 '搜尋字串' 內容的那一行!
--color=auto :可以將找到的關鍵詞部分加上顏色的顯示!

示例:
grep -c -n -i 'root' /etc/passwd
cat /etc/passwd | grep -c -n -i 'root'

# 遞迴搜查 
grep ‘#!/bin/*’ *           #在當前目錄下的檔案搜尋帶'#!/bin/*'行的檔案
grep -r '#!/bin/*' *        #在當前目錄及其子目錄下搜尋'#!/bin/*'行的檔案
grep -l -r ‘#!/bin/*’ *     #在當前目錄及其子目錄下搜尋'#!/bin/*'行的檔案,但是不顯示匹配的行,只顯示匹配的檔案

5. 驗證遠端伺服器是否可以ping同,並根據結果做相應的處理

#驗證資料庫伺服器地址是否可以ping成功
ping -c 1 $dbIP > /dev/null 2>&1
if [ $? -eq 0 ]; then
	echo ... ping $dbIP successfully
else
	echo ... ping $dbIP defeated
	exit 1
fi

5.1 ping 命令

在shell 指令碼中ping命令一定要但引數 -c (接收的次數)因為linux 的ping命令不會自動停止

5.2 linux 中特殊變數 $0 $1 $2 ... $n $* [email protected]  $# $$ $?

  • $0  :  當前指令碼的檔名  
  • $n  :  傳遞給指令碼或函式的引數。n 表示第幾個引數。例如,第一個引數是$1,第二個引數是$2。  
  • $# : 傳遞給指令碼或函式的引數個數。  
  • $*  : 傳遞給指令碼或函式的 所有引數 。  
  • [email protected]:傳遞給指令碼或函式的所有引數。被雙引號(" ")包含時,與 $* 稍有不同。  
  • $?  :上個命令的退出狀態,或函式的返回值。執行成功會返回 0,失敗返回 非0。  
  • $$ :當前Shell程序ID。對於 Shell 指令碼,就是這些指令碼所在的程序ID。 
$* 和 [email protected] 的區別  
       $* 和 [email protected] 都表示傳遞給函式或指令碼的所有引數,不被雙引號(" ")包含時,都以"$1" "$2" … "$n" 的形式輸出所有引數。 但是當它們被雙引號(" ")包含時,"$*" 會將所有的引數作為一個整體,以"$1 $2 … $n"的形式輸出所有引數;"[email protected]" 會將各個引數分開,以"$1" "$2" … "$n" 的形式輸出所有引數。 
./test.sh "a" "b" "c" "d"
print each param from "$*"
    a b c d
print each param from "[email protected]"
a
b
c
d
說明:雙引號包含時,"$*"的引數被當做一個整體,而"[email protected]"還是遍歷每一個引數

5.3 重定向問題

參考文件: linux中的重定向問題

簡而言之,輸入重定向是指把檔案匯入到命令中, 輸出重定向是指把原本要輸出到螢幕的資料資訊寫入到指定的檔案。而輸出重定向又分為標準輸出重定向和錯誤輸出重定向

5.3.1 重定向符號

  • 標準輸入重定向(STDIN 檔案描述為 0):預設從鍵盤輸入,也可以重其它檔案輸入或命令輸入,使用的方式為 <

   重定向符號:<

wc -l < reademe.txt
  標準輸入重定向符號: << 分界符   (從標準輸入中(鍵盤)讀入,直到遇見分界符才停止)
wc -m << BYE
> hello
> world
>BYE
12
  • 標準輸出重定向(STDOUT 檔案描述為 1):預設輸出到螢幕,使用的方式為 1>

    命令 > 檔案  : 將標準輸出重定向到一個檔案中 (清空原來檔案的資料)

    命令 >> 檔案:將標準輸出重定向到一個檔案中(追加到原有內容的後面)   

  • 錯誤輸出重定向(STDERR 檔案描述為 2):預設輸出到螢幕, 使用的方式為 2>

    命令 2> 檔案  : 將錯誤輸出重定向到一個檔案中 (清空原來檔案的資料)   

    命令 >> 檔案 : 將錯誤輸出重定向到一個檔案中(追加到原有內容的後面)   

組合形式:

    命令 >> 檔案 2 > &1

    命令 &>>檔案

   上面兩個命令等價: 將標準輸出與錯誤輸出共同寫入到檔案中(追加到原始檔的後面)

5.3.2 linux的“黑洞”檔案

ls -al 1> list.txt 2> /dev/null
將顯示的資料,正確的輸出到 list.txt ;錯誤的資料則予以丟棄! /dev/null ,可以說成是黑洞裝置。為空,即不儲存。


6. shell中呼叫java命令,並接受返回值

# 執行java 命令並將返回值輸入到變數

result=$(java -jar ./install_linux.jar)

if [ ${result} = "true" ]; then
	echo ... execute dbscripts finished
	#刪除資料庫指令碼檔案
	rm -rf ./server/dbscript
else
	echo ... execute dbscripts have met a error. please check the dbscript or network
	exit 1
fi
注意在 java程式碼中必須要輸出(System.out.println("true")),其實它還是根據輸出來判斷的;


7. Linux中tomcat開機自啟動指令碼

參考文獻: Linux tomcat開機自啟動

第一步:在/etc/init.d檔案下建立啟動shell指令碼, 並編寫自啟動指令碼

vi /etc/init.d/tomcat

第二步: 設定指令碼許可權   

chmod 755 tomcat

第三步:將這個shell檔案掛載到/etc/rc2.d下

/etc/rc.d/rcx.d/下的檔案均為符號連結,最終絕大部分都是都是連結到/etc/rc.d/init.d下面。

    linux的/etc/rcX.d/目錄中的數字代表開機啟動時不同的run level,也就是啟動的順序,用ln命令將tomcat的連結鏈過去:rcX.d目錄下的命名規則是很有講究的,根據不同需要可能是S開頭,也可能是K開頭,之後的數字代表他們的啟動順序; linux在載入過程中載入到init程式時,會去讀/etc/rc.d/rcx.d/下的檔案,均為符號連結,最終絕大部分都是都是連結到/etc/rc.d/init.d下面 ,我們可以知道,/etc/rc.d/init.d目錄下面的都是開啟啟動指令碼檔案,用來啟動相應的程式
ln -s /etc/init.d/tomcat /etc/rc2.d/S16tomcat

第四步:設定指令碼開機自啟動

chkconfig --add /etc/init.d/tomcat

第五步:使用linux系統服務命令 service 管理tomcat服務

service tomcat status # 檢視服務狀態    
service tomcat start  # 啟動服務
service tomcat stop   # 停止服務
service tomcat restart  #重啟服務

7.1 編寫tomcat自啟動指令碼

#!/bin/sh
# chkconfig: 345 99 10
# description: Auto-starts tomcat
# /etc/init.d/tomcatd
# Tomcat auto-start
# Source function library.
#. /etc/init.d/functions
# source networking configuration.
#. /etc/sysconfig/network

RETVAL=0

#獲取jdk的絕對路徑
java_relative_home=/usr/zlits_dms/jdk
export JAVA_HOME=$(readlink -f ${java_relative_home})
export JRE_HOME=$(readlink -f ${java_relative_home}/jre)
tomcat_relative_home=/usr/zlits_dms/server/tomcat
export CATALINA_HOME=$(readlink -f ${tomcat_relative_home})
#服務名稱
service_name=tomcat

start()
{
        if [ -f $CATALINA_HOME/bin/startup.sh ]; then
            echo $"Starting Tomcat"
                $CATALINA_HOME/bin/startup.sh
            RETVAL=$?
            echo " OK"
            return $RETVAL
        fi
}
stop()
{
        if [ -f $CATALINA_HOME/bin/shutdown.sh ]; then
            echo $"Stopping Tomcat"
                $CATALINA_HOME/bin/shutdown.sh
            RETVAL=$?
            sleep 1
            ps -fwwu root | grep tomcat|grep -v grep | grep -v PID | awk '{print $2}'|xargs kill -9
            echo " OK"
            # [ $RETVAL -eq 0 ] && rm -f /var/lock/...
            return $RETVAL
        fi
}
status()
{
    svrs=`ps aux | grep root | grep tomcat | grep -v grep | grep -v status | wc -l`
    if [ $svrs -gt 0 ]; then
        echo -e "\033[1;32;40m${service_name} is running now!\033[0m"
    else
        echo -e "\033[1;31;40m${service_name} is not running now!\033[0m"
    fi
}

case "$1" in
 start) 
        start
        ;;
 stop)  
        stop
        ;;
 status)  
        status
        ;;                                           
 restart)
         echo $"Restaring Tomcat"
         $0 stop
         sleep 1
         $0 start
         ;;
 *)
        echo $"Usage: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac
exit $RETVAL

7.1.1 shell case 條件測試語句形式和函式呼叫

case 變數值 in                case 輸入的字元 in
模式1)                        [a-z]|[A-Z])
    命令序列 1                    提示為字母
    ;;                           ;;
模式2)                        [0-9])
    命令序列 2                    提示為陣列
    ;;                           ;;
*)                            *)
    預設命令序列                   預設命令
esac                          esac

由於 shell script 的執行方式由上向下、由左向右,因此在shell script當中的function的設定一定要在程式的最前面,這樣才能夠在執行的時候找到可用的程式段;

function fname() {
    程式碼塊;
}
fanme # 呼叫函式

7.1.2 一個shell指令碼中呼叫另一個shell指令碼的方式

參考文獻:跨shell指令碼的呼叫

先來說一下主要以下有幾種方式及呼叫方式:

  • fork: 如果指令碼有執行許可權的話,path/foo.sh。如果沒有,sh path/foo.sh
  • exec: exec path/foo.sh
  • source: source path/foo.sh  等價於 . /path/foo.sh

fork

fork 是最普通的, 就是直接在腳本里面用 path/foo.sh 來呼叫
foo.sh 這個指令碼,比如如果是 foo.sh 在當前目錄下,就是 ./foo.sh。執行的時候 terminal 會新開一個子 Shell 執行指令碼 foo.sh,子 Shell 執行的時候, 父 Shell 還在。子 Shell 執行完畢後返回父 Shell。 子 Shell 從父 Shell 繼承環境變數,但是子 Shell 中的環境變數不會帶回父 Shell。

exec

execfork 不同,不需要新開一個子 Shell 來執行被呼叫的指令碼. 被呼叫的指令碼與父指令碼在同一個 Shell 內執行。但是使用 exec 呼叫一個新指令碼以後, 父指令碼中 exec 行之後的內容就不會再執行了。這是 execsource 的區別.

source

source 操作也成為 . 操作;

fork 的區別是不新開一個子 Shell 來執行被呼叫的指令碼,而是在同一個 Shell 中執行. 所以被呼叫的指令碼中宣告的變數和環境變數, 都可以在主指令碼中進行獲取和使用。source方式的結果是兩者在同一程序裡執行。該方式相當於把兩個指令碼先合併再執行。

Command Explanation
fork 新開一個子 Shell 執行,子 Shell 可以從父 Shell 繼承環境變數,但是子 Shell 中的環境變數不會帶回給父 Shell。
exec 在同一個 Shell 內執行,但是父指令碼中 exec 行之後的內容就不會再執行了
source 在同一個 Shell 中執行,在被呼叫的指令碼中宣告的變數和環境變數, 都可以在主指令碼中進行獲取和使用,相當於合併兩個指令碼在執行。

7.1.3 ps命令 xargs 命令 kill 命令

#原文命令
ps -fwwu root | grep tomcat|grep -v grep | grep -v PID | awk '{print $2}'|xargs kill -9

#自己命令
ps -aux | grep root | grep tomcat | grep -v grep |awk '{pirnt $2}' | xargs kill -9

#命令 
ps -aux 
#輸出格式
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
  USER:該 process 屬於那個使用者賬號的 
  PID :該 process 的號碼 
  %CPU:該 process 使用掉的 CPU 資源百分比 
  %MEM:該 process 所佔用的實體記憶體百分比 
  VSZ :該 process 使用掉的虛擬記憶體量 (Kbytes) 
  RSS :該 process 佔用的固定的記憶體量 (Kbytes) 
  TTY :該 process 是在那個終端機上面運作,若與終端機無關,則顯示 ?
  STAT:該程式目前的狀態,主要的狀態有 
  R :該程式目前正在運作,或者是可被運作 
  S :該程式目前正在睡眠當中 (可說是 idle 狀態),但可被某些訊號 signal) 喚醒。 
  T :該程式目前正在偵測或者是停止了 
  Z :該程式應該已經終止,但是其父程式卻無法正常的終止他,造成 zombie (疆屍) 程式的狀態 
  START:該 process 被觸發啟動的時間 
  TIME :該 process 實際使用 CPU 運作的時間 
  COMMAND:該程式的實際指令

xargs 命令

參考文獻:xargs詳解

xargs能夠處理管道或者stdin並將其轉換成特定命令的命令引數。xargs也可以將單行或多行文字輸入轉換為其他格式,例如多行變單行,單行變多行。xargs的預設命令是echo,空格是預設定界符。這意味著通過管道傳遞給xargs的輸入將會包含換行和空白,不過通過xargs的處理,換行和空白將被空格取代。xargs是構建單行命令的重要元件之一

cat test.txt

a b c d e f g
h i j k l m n
o p q
r s t
u v w x y z
cat test.txt | xargs

a b c d e f g h i j k l m n o p q r s t u v w x y z
echo '--help' | xargs cat
# echo '--help' | xargs cat 等價於 cat --help ,就是xargs將其接受的字串 --help 做成cat的一個命令引數來執行cat命令,
#同樣  echo 'test.c test.cpp' | xargs cat 等價於 cat test.c test.cpp 此時會將test.c和test.cpp的內容都顯示出來。

kill 命令

kill -option PID
 -option
    -l 訊號([ 2 中斷 同Ctrl + c ] [3 退出 同Ctrl+\] [9 無條件強行終止] [19 暫停])

    只有第9種訊號(SIGKILL)才可以無條件終止程序,其他訊號程序都有權利忽略。  

7.1.4 Shell中各種括號的詳解

參考文件:shell中的各種括號詳解

小括號 () : 

    命令組。括號中的命令將會新開一個子shell順序執行所以括號中的變數不能夠被指令碼餘下的部分使用。括號中多個命令之間用分號(或&&, 主要區別)隔開,最後一個命令可以沒有分號,各命令和括號之間不必有空格。

    命令替換。 等同於兩個反單引號,`commond`。

    宣告陣列。 declare -a array_name; array_name=( 1 2 3 );

雙小括號 (()) :

    (1)整數擴充套件。這種擴充套件計算是整數型的計算,不支援浮點型。((exp))結構擴充套件並計算一個算術表示式的值,如

result=$((5-3))

    註釋:對於本小節開頭部分引用的文獻中整數擴充套件部分所說的,當表示式的值為非零則。。。自己可能沒有理解博主意思,感覺不對,沒有引入到本文中

    (2)常用於算術運算比較。雙括號中的變數可以不使用$符號字首。括號內支援多個表示式用逗號分開。 只要括號中的表示式符合C語言運算規則,

  • 比如可以直接使用for((i=0;i<5;i++)), 如果不使用雙括號, 則為for i in `seq 0 4`或者for i in {0..4}。
  • 再如可以直接使用if (($i<5)), 如果不使用雙括號, 則為if [ $i -lt 5 ]。

(3)單純用 (( )) 也可重定義變數值,比如 a=5; ((a++)) 可將 $a 重定義為6

中括號 [] :

    Test和[]具有相同的功效(判斷符號);

    檔案:-e -f -d -b -L

    許可權: -w -r -x -u -g -k -s

    兩個檔案比較:-nt  -ot -ef

    整數判斷: -eq -ne -gt -lt -ge -le

    字串判斷: -z -n = !=

    多重條件判斷: -a -0 !

if [ -r file1 -a -x file1 ]; then
    echo file1 has r x right;
fi
if test -r file1 -a -x file1 ; then
    echo file1 has r x right;
fi 

雙中括號 [[]] :

    使用[[ ... ]]條件判斷結構,而不是[ ... ],能夠防止指令碼中的許多邏輯錯誤。比如,&&、||、<和> 操作符能夠正常存在於[[ ]]條件判斷結構中,但是如果出現在[ ]結構中的話,會報錯。比如可以直接使用if [[ $a != 1 && $a != 2 ]], 如果不適用雙括號, 則為if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ]。

大括號 {} :

    大括號拓展。(通配(globbing))將對大括號中的檔名做擴充套件。在大括號中,不允許有空白,除非這個空白被引用或轉義。

# ls {ex1,ex2}.sh 
ex1.sh ex2.sh 
# ls {ex{1..3},ex4}.sh 
ex1.sh ex2.sh ex3.sh ex4.sh 
# ls {ex[1-3],ex4}.sh 
ex1.sh ex2.sh ex3.sh ex4.sh

     (2)程式碼塊,又被稱為內部組,這個結構事實上建立了一個匿名函式 。與小括號中的命令不同,大括號內的命令不會新開一個子shell執行,即指令碼餘下部分仍可使用括號內變數。括號內的命令間用分號隔開,最後一個也必須有分號。{}的第一個命令和左括號之間必須要有一個空格。

(cmd1;cmd2;cmd3)和{ cmd1;cmd2;cmd3}

    (1)單小括號,(cmd1;cmd2;cmd3) 新開一個子shell順序執行命令cmd1,cmd2,cmd3, 各命令之間用分號隔開, 最後一個命令後可以沒有分號。

    (2)單大括號,{ cmd1;cmd2;cmd3;} 在當前shell順序執行命令cmd1,cmd2,cmd3, 各命令之間用分號隔開, 最後一個命令後必須有分號, 第一條命令和左括號之間必須用空格隔開。

特殊替換:

形式 說明
${var} 變數本來的值
${var:-word} 如果變數 var 為空或已被刪除(unset),那麼返回 word,但不改變 var 的值。
${var:=word} 如果變數 var 為空或已被刪除(unset),那麼返回 word,並將 var 的值設定為 word。
${var:?message} 如果變數 var 為空或已被刪除(unset),那麼將訊息 message 送到標準錯誤輸出,可以用來檢測變數 var 是否可以被正常賦值。
若此替換出現在Shell指令碼中,那麼指令碼將停止執行。
${var:+word} 如果變數 var 被定義,那麼返回 word,但不改變 var 的值。

模式匹配替換:

${var%pattern},${var%%pattern},${var#pattern},${var##pattern}
${var%pattern}
#shell在variable中查詢,看它是否依給的模式pattern結尾,如果是,就從命令列把variable中的內容 去掉 右邊最短 的匹配模式 
${var%%pattern}
#shell在variable中查詢,看它是否依給的模式pattern結尾,如果是,就從命令列把variable中的內容 去掉 右邊最長 的匹配模式
${var#pattern}
#shell在variable中查詢,看它是否依給的模式pattern開始,如果是,就從命令列把variable中的內容 去掉 左邊最短 的匹配模式
${var##pattern}
#shell在variable中查詢,看它是否依給的模式pattern開始,如果是,就從命令列把variable中的內容 去掉 左邊最長 的匹配模式

這四種模式中都不會改變variable的值,其中,只有在pattern中使用了*匹配符號時,%和%%,#和##才有區別。結構中的pattern支援萬用字元,*表示零個或多個任意字元,?表示僅與一個任意字元匹配,[...]表示匹配中括號裡面的字元,[!...]表示不匹配中括號裡面的字元

str=/home/guest/shell/hello.sh
${str#/*/} ## guest/shell/hello.sh
${str##/*/} ## hello.sh

字串提取和替換:

${var:num},${var:num1:num2},${var/pattern1/pattern2},${var//pattern1/pattern2}
${var:num}
#shell在var中提取第num個字元到末尾的所有字元。若num為正數,從左邊0處開始;
#若num為負數,從右邊開始提取字串,提起num個字串,形式:${var:-2}或${var:(-2)}。
#例如:
var=1234567890
echo ${var:4} #567890
echo ${var:-4} #0987
${var:num1:num2}
# num1是位置,num2是長度。表示從$var字串的第num1個位置開始提取長度為num2的子串。
# num2不能為負數,當大於字串長度時,取最大長度。
var=1234567890
echo ${var:3:3}  #456
echo ${var:3:13} #4567890
${var/pattern1/pattern2}
# 表示將var字串的第一個匹配的pattern1替換為另一個pattern2。
var=1234563337890
echo ${var/3/a}  #12a4563337890
${var//pattern1/pattern2}
# 表示將var字串的匹配到的pattern1全部替換為另一個pattern2。
var=1234563337890
echo ${var//3/a}  #12a456aaa7890

7.2 chkconfig 命令

參考文件:Linux chkconfig命令