首頁 > 軟體

Linux Shell 使用筆記

2020-06-16 17:30:19

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


IT145.com E-mail:sddin#qq.com