2021-05-12 14:32:11
Linux Shell 使用筆記
1.背景
Linux Shell是一種基本功,由於怪異的語法加之較差的可讀性,通常被Python等指令碼代替。既然是基本功,那就需要掌握,畢竟學習Shell指令碼的過程中,還是能了解到很多Linux系統的內容。Linux指令碼大師不是人人都可以達到的,但是用一些簡單的Shell實現一些常見的基本功能還是很有必要的。
2.正題
1) 熱身
下面的例子展示了如何向指令碼傳遞引數、指令碼如何獲取引數、if-else判斷、變數的使用等基本內容。
#!/bin/bash
if [[ $# -lt 1 ]]; then
echo "args count must > 1"
echo "Uage: bash +x example01.sh [args...]"
exit
fi
arg=$1
if [[ $arg -gt 10 ]]; then
echo "$arg > 10"
else
echo "$arg < 10"
fi
這個指令碼的呼叫方式如下:
bash +x example01.sh 52).陣列、函數傳引數,迴圈
下面的例子展示了陣列、函數、迴圈等基本使用。
#!/bin/bash
if [[ $# -lt 1 ]]; then
echo "args count must > 1"
echo "Uage: bash +x example01.sh [args...]"
exit
fi
args=$@
for arg in $args; do
echo $arg
done
function fun() {
echo $1
}
fun "hello shell"
fun2() {
echo "Linux"
}
fun2注意,函數fun中的$1,獲取的是函數引數,不是指令碼呼叫時傳入的引數。$@ 是獲取指令碼呼叫時傳入的參數列。
3).while 迴圈以及其他幾種迴圈、case、表示式expr的使用
#!/bin/bash
if [[ $# -lt 1 ]]; then
echo "args count must > 1"
echo "Uage: bash +x example01.sh [args...]"
exit
fi
case $1 in
"install" )
echo "operation type is install"
;;
"uninstall" )
echo "operation type is uninstall"
;;
* )
echo "operation type is not support"
;;
esac
for ((i=0;i<3;i++))
do
if ((i==1))
then
continue
fi
echo $i
done
for i in `seq 5`
do
echo "loop $i"
done
注意這裡的case * 並不是所有,而是輸入值不在case中,相當於default. 在迴圈中可以使用continue/break等關鍵字,非常類似Java等其他語言的迴圈。
4).指令碼之間互相參照
通過source 或者 . 的方式可以參照另一個指令碼中的函數或者變數
first.sh
function fun(){
echo "i am from first."
}
file=firstsecond.sh
. first.sh
fun
echo $file
使用bash +x second.sh執行,在second.sh 中可以呼叫fun函數和使用file變數。
這裡的.和source都可以實現參照first檔案中的變數。注意: 如果同時參照了多個指令碼的同一個變數名的變數,後面的值會覆蓋前面的變數而不會報錯。
5).關於錯誤處理
a)在shell中有一個變數 $? ,這個變數記錄的是上次指令碼執行的結果,如果正常結束則是0,否則是非0值;
b)如果在shell指令碼中通過set -o errexit來實現遇到錯誤就退出,這樣能夠避免產生更多的錯誤;
c)在shell執行過程中如果出錯,可以通過重定向的方式,輸出到檔案中,比如Command >> filename2>&1
6).字典
shell中的字典是非常好的資料結構,能夠很方便地處理設定
#!/bin/bash
set -o errexit
hput(){
eval "hkey_$1"="$2"
}
hget(){
eval echo '${'"hkey_$1"'}'
}
hput k1 v1
hget k1
declare -A dic
dic=([key1]="value1" [key2]="value2" [key3]="value3")
echo ${dic["key1"]}
# output all key
echo ${!dic[*]}
#outpull all value
echo ${dic[*]}
# access all
for key in $(echo ${!dic[*]})
do
echo "$key : ${dic[$key]}"
done
執行之後,輸出如下:
v1
value1
key3 key2 key1
value3 value2 value1
key3 : value3
key2 : value2
key1 : value1
7).文字處理
sed 命令能夠對對文字進行操作。
比如有一個檔案sedfile,內容如下:
1
2
3
4
5執行 "sed '1,3d' sedfile,則會輸出4,5 兩行,即對1,2,3行做了刪除處理,注意這時檔案裡面並沒有刪掉這兩行。
除了刪除之外,還可以做替換操作。
root@Ubuntu:~/codelab# sed 's/1/0/g' sedfile
0
2
3
4
5
root@ubuntu:~/codelab# cat sedfile
1
2
3
4
5我們發現,在輸出時,將1替換成了0;
文字處理還有一個非常強大的工具-awk
我們首先看看awk的基本處理-按照逗號(,)分割獲取想要的文字;
root@ubuntu:~/codelab# cat awkfile
this,is,a,awk,file
this,is,a,awk,file
root@ubuntu:~/codelab# cat awkfile | awk -F ',' '{print $0}'
this,is,a,awk,file
this,is,a,awk,file
root@ubuntu:~/codelab# cat awkfile | awk -F ',' '{print $1}'
this
this
root@ubuntu:~/codelab#
這裡我們可以看到awk可以按照任意形式分割文字,然後輸出;
8).特殊變數和值
下列變數通常具有固定意義
$# 表示變數的個數,常用於迴圈
$@ 當前命令列所有引數。置於雙引號中,表示個別引數
$* 當前命令列所有引數。置於雙引號中,表示將命令列所有引數當初一個單獨引數
$-(連字號) 在參照數給予Shell的選項
$? 表示上一個命令退出的狀態
$$ 表示當前進程編號
$0 表示當前程式名稱
$! 表示最近一個後台命令的進程編號
$HOME 表示當前使用者根目錄
$IFS 表示內部的欄位分隔符
$LANG 當前locale預設名稱
$PATH 環境變數
$PPID 父進程編號
$PWD 當前工作目錄下列特殊值可以幫助排查問題
0 成功退出
>0 退出失敗
1-125 命令退出失敗,失敗返回的相關值由程式定義(譬如,程式內退出只執行 exit 2,則返回為2)
126 命令找到了,但無法執行
127 命令找不到
>128 命令因受到信號而死亡9.定時任務
windows系統下有定時任務,在linux系統上也一樣有定時任務。使用系統自帶的crontab即可實現;
我的系統上執行 cat /etc/crontab的輸出如下:
root@ubuntu:~/codelab# cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
從這裡我們可以看出cron是如何使用的,這裡設定了cron使用shell,下面是命令的設定方式。
minute: 表示分鐘,可以是從0到59之間的任何整數。
hour:表示小時,可以是從0到23之間的任何整數。
day:表示日期,可以是從1到31之間的任何整數。
month:表示月份,可以是從1到12之間的任何整數。
week:表示星期幾,可以是從0到7之間的任何整數,這裡的0或7代表星期日。
command:要執行的命令,可以是系統命令,也可以是自己編寫的指令碼檔案。我們可以使用如下一些基礎命令;
usage: crontab [-u user] file
crontab [ -u user ] [ -i ] { -e | -l | -r }
(default operation is replace, per 1003.2)
-e (edit user's crontab)
-l (list user's crontab)
-r (delete user's crontab)
-i (prompt before deleting user's crontab)10).技巧
a)判斷引數是否是數位。
#!/bin/sh
#1. $1是指令碼的第一個引數,這裡作為awk命令的第一個引數傳入給awk命令。
#2. 由於沒有輸入檔案作為輸入流,因此這裡只是在BEGIN塊中完成。
#3. 在awk中ARGV陣列表示awk命令的引數陣列,ARGV[0]表示命令本身,ARGV[1]表示第一個引數。
#4. match是awk的內建函數,返回值為匹配的正規表示式在字串中(ARGV[1])的起始位置,沒有找到返回0。
#5. 正規表示式的寫法已經保證了匹配的字串一定是十進位制的正整數,如需要浮點數或負數,僅需修改正則即可。
#6. awk執行完成後將結果返回給isdigit變數,並作為其初始化值。
#7. isdigit=`echo $1 | awk '{ if (match($1, "^[0-9]+$") != 0) print "true"; else print "false" }' `
#8. 上面的寫法也能實現該功能,但是由於有多個進程參與,因此效率低於下面的寫法。
isdigit=`awk 'BEGIN { if (match(ARGV[1],"^[0-9]+$") != 0) print "true"; else print "false" }' $1`
if [[ $isdigit == "true" ]]; then
echo "This is numeric variable."
number=$1fib) 根據系統給變數賦值,確保可移植性
#1. 通過uname命令獲取當前的系統名稱,之後再根據OS名稱的不同,給PING變數賦值不同的ping命令的全稱。
osname=`uname -s`
#2. 可以在case的條件中新增更多的作業系統名稱。
case $osname in
"Linux")
PING=/usr/sbin/ping ;;
"FreeBSD")
PING=/sbin/ping ;;
"SunOS")
PING=/usr/sbin/ping ;;
*)
;;
esac
3.總結
這些只是shell開發中的最基礎部分,shell 其實是一種非常高效、強大的語言,不斷學習和積累一定會越來越熟練。
本文永久更新連結地址:http://www.linuxidc.com/Linux/2016-10/136040.htm
相關文章