初學者編寫bash腳本教程html
bash是命令語言解釋器。普遍用於各類gun/unix系統上的默認命令解釋器。全程叫作「Bourne-Again SHell」mysql
shell是一個宏處理器,容許執行交互式或非交互式的命令。linux
腳本容許自動執行,不然會一個接一個命令交互執行。程序員
shell容許你經過命令與計算機交互,從而檢索或存儲數據、處理信息和其它各類簡單甚至很是複雜的任務。sql
因此:你天天都會執行date cal pwd lsdocker
script就是把上邊的4個命令放在一個文本里,而後一塊兒執行。shell
bash是許多GNU/Linux系統上的默認解釋器編程
查看默認解釋器執行命令:echo $SHELL
ubuntu
[root@localhost ~]# echo $SHELL /bin/bash
#!
shebang,定義腳本的shell解釋器,寫在腳本的第一行如:數組
#!/bin/bash
經過which bash
查找bash可執行二進制文件的完整路徑。
要執行腳本,就要給腳本加執行的權限:chmod +x filename
經過file 命令查看文件的類型 file filename
[root@localhost ~]# file a.sh a.sh: Bourne-Again shell script, ASCII text executable [root@localhost ~]# file epel-7.repo epel-7.repo: ASCII text
一、指定解釋器執行腳本
[root@localhost ~]# /bin/bash date.sh Sat Jul 14 09:01:39 UTC 2018
二、腳本文件頭定義shebang,文件加執行權限
[root@localhost ~]# cat date.sh #!/bin/bash date [root@localhost ~]# chmod +x date.sh [root@localhost ~]# ./date.sh Sat Jul 14 09:02:41 UTC 2018
在linux中絕對路徑就是從根/
開始,如:/usr/local/httpd
就是路徑開頭沒有根/
,如:cd abc/test/
cd
不加任何參數,切換到當前用戶home目錄。
cd ~
都是切換到當前用戶home目錄。
cd 加路徑
切換到目標路徑,如:cd /usr/local
[root@localhost ~]# echo '#!/bin/bash' > hello.sh [root@localhost ~]# echo 'echo "hello world"' >> hello.sh [root@localhost ~]# cat hello.sh #!/bin/bash echo "hello world" [root@localhost ~]# chmod +x hello.sh [root@localhost ~]# ./hello.sh hello world
vi backup.sh #建立腳本 # !/bin/bash tar czf /tmp/root.tar /root/abc chmod +x backup.sh #加執行權限 ./backup.sh #執行腳本 [root@localhost]# ls /tmp/root.tar #驗證執行結果 /tmp/root.tar
雙引號"" 容許用過$符號引用其餘變量值
單引號'' 禁止引用其餘變量值,$視爲普通字符
反撇號`` 將命令執行的記過輸出給變量;如:
sed -i s/"B"/"b"/g `grep -rl "B" --exclude="*.sql" ceshi/*` 將grep獲得的文件傳輸給sed使用
設置變量的做用範圍
格式:
export 變量名
export 變量名=變量值
清除變量名:
unset 變量名
自定義變量 [root@ceshi ~]# export a #自定義變量a [root@ceshi ~]# export b=222 #自定義變量b [root@ceshi ~]# a=111 #給變量a賦值 [root@ceshi ~]# echo $a #打印變量a的值 111 [root@ceshi ~]# echo $b #打印變量b的值 222 清除變量: [root@ceshi ~]# unset a #清除變量a [root@ceshi ~]# unset b #清除變量b [root@ceshi ~]# echo $a #輸出爲空 [root@ceshi ~]# echo $b
全局配置文件:/etc/profile
用戶配置文件:~/.bash_profile
set 命令能夠查看全部的shell變量,其中包括環境變量
表示爲:$n (n爲1-9之間的數字)
#./test.sh one two three four five six
$0 表示腳本文件名自己
$1 表示one
$2 表示two
依次類推
$n 這個程式的第n個參數值,n=1..9
$@
跟$*相似,可是能夠看成數組用變量是編程的本質。變量容許程序員在整個腳本中存儲、修改和重用數據。
#!/bin/bash greeting="Welcome" user=$(whoami) day=$(date +%A) echo "$greeting back $user! Today is $day." echo "Your bash shell version is:$BASH_VERSION."
解釋腳本:
第一部分:
shebang 指定shell解釋器
greeting:定義一個變量,並賦值一個字符串值。
user:定義一個變量,賦值是經過一個命令替換技術來完成的。經過運行whoami獲取當前的用戶名,而後賦值給user。
day:定義一個變量,賦值同上;+%A表明只顯示周幾。
第二部分:
使用echo向終端打印信息,$greeting用來調用變量對應的值Welcome;$user一樣用來調用變量對應的用戶名;date也同樣。
注意:不要使用大寫命名私有變量,由於大寫變量名都是內置變量。若是覆蓋內置變量,可能致使功能失調。
[root@localhost ~]# a=5 #定義變量 [root@localhost ~]# b=6 [root@localhost ~]# echo $a #調用變量 5 [root@localhost ~]# echo $b 6 [root@localhost ~]# echo $[$a+$b] #變量算數 11
利用變量更新備份腳本,生成更有意義的文件名:
vi backup.sh
#!/bin/bash # this bash script is backup a general user's home directory to /tmp/ user=$(whoami) input=/home/$user output=/tmp/${user}_home$(date +%Y-%m-%d_%H%M%S).tar.gz tar czf $output $input echo "Backup of $input completed!! Details about the output backup file:" ls -l $output
腳本第五行:${parameter}叫參數展開,將花括號中的內容挨個和外面的內容結合。
[abc@localhost ~]$ ./backup.sh tar: Removing leading `/' from member names Backup of /home/abc completed!! Details about the output backup file: -rw-rw-r-- 1 abc abc 741 Jul 14 13:59 /tmp/abc_home2018-07-14_135933.tar.gz
一般在GNU/Linux命令行上執行的命令要麼產生輸出,要麼要求輸入,要麼拋出錯誤消息。這是shell腳本的基本概念,也是使用GNU/Linux命令行的基本概念。
每次執行命令時,可能會發生三種可能的結果。第一個場景是命令將產生一個預期的輸出,其次,該命令將生成一個錯誤,最後,您的命令可能根本不會產生任何輸出。
[abc@localhost ~]$ ls backup.sh backup.sh
重定向標識符:「>」
重定向會將 標準輸出 重定向到指定目標。
[abc@localhost ~]$ touch foobar [abc@localhost ~]$ ls foobar barfoo ls: cannot access barfoo: No such file or directory foobar [abc@localhost ~]$ ls foobar barfoo > stdout.txt ls: cannot access barfoo: No such file or directory [abc@localhost ~]$ cat stdout.txt foobar
重定向將 標準錯誤 重定向到指定目標。
[abc@localhost ~]$ ls foobar barfoo 2> stderr.txt foobar [abc@localhost ~]$ cat stderr.txt ls: cannot access barfoo: No such file or directory
重定向將 標準輸出和標準錯誤 一塊重定向到指定目標。
[abc@localhost ~]$ ls foobar barfoo &> stdoutandstderr.txt [abc@localhost ~]$ cat stdoutandstderr.txt ls: cannot access barfoo: No such file or directory foobar
追加劇定向輸出,不覆蓋文件,直接追加到文件結尾。
[abc@localhost ~]$ ls test.sh ls: cannot access test.sh: No such file or directory
重定向將 標準錯誤 重定向到指定目標。
[abc@localhost ~]$ ls foobar barfoo 2> stderr.txt foobar [abc@localhost ~]$ cat stderr.txt ls: cannot access barfoo: No such file or directory
一般終端輸入來自鍵盤,因此輸入的任何內容都稱爲stdin(標準輸入)。
接受來自文件的命令輸入。使用「<」符號接受文件輸入。
咱們先用cat 命令,經過標準輸入而後,重定向到file.txt:
[abc@localhost ~]$ cat > file.txt hello world. welcome backup. [abc@localhost ~]$ cat file.txt hello world. welcome backup.
咱們再用cat命令,經過< 符號輸入file.txt的內容:
[abc@localhost ~]$ cat < file.txt hello world. welcome backup.
[root@localhost log]# cat >aaa.txt<<EOF > hello world > EOF [root@localhost log]# cat aaa.txt hello world
[root@localhost log]# cat >>aaa.txt<<EOF > 123456789 > HELLO WORLD > EOF [root@localhost log]# cat aaa.txt hello world 123456789 HELLO WORLD
從鍵盤或文件中獲取標準輸入:read命令
語法:read 變量名
[abc@localhost ~]$ read a abc [abc@localhost ~]$ echo $a abc [abc@localhost ~]$ echo "the word you entered is: $a" the word you entered is: abc [abc@localhost ~]$ read a1 a2 #同時輸入兩個字段 aaa bbb [abc@localhost ~]$ echo $a1 aaa [abc@localhost ~]$ echo $a2 bbb
詳細見:https://blog.51cto.com/506554897/2114407
以前的backup腳本執行時有個錯誤:
tar: Removing leading "/" from member names
消息告訴咱們,絕對路徑已被刪除,從而提取了壓縮文件,而不是覆蓋任何現有文件。並無形成任何影響。
所以我能夠利用重定向消除這種沒必要要的信息。經過重定向stderr到/dev/null,/dev/null做爲數據接收器,它丟棄任何重定向到它的數據,能夠用man null查看詳細。
咱們將腳本修改以下:
[abc@localhost ~]$ vi backup.sh #!/bin/bash # this bash script is backup a general user's home directory to /tmp/ user=$(whoami) input=/home/$user output=/tmp/${user}_home$(date +%Y-%m-%d_%H%M%S).tar.gz tar czf $output $input 2> /dev/null echo "Backup of $input completed!! Details about the output backup file:" ls -l $output
[abc@localhost ~]$ ./backup.sh Backup of /home/abc completed!! Details about the output backup file: -rw-rw-r-- 1 abc abc 893 Jul 14 14:59 /tmp/abc_home2018-07-14_145919.tar.gz
執行後沒有了報錯信息。
##名詞
函數容許程序員組織和重用代碼,從而提升了整個腳本的效率、執行速度和可讀性。
當注意到腳本包含兩行相同的代碼時,能夠考慮使用一個函數。
函數是將不一樣命令的組號組合成當個命令的方法。若是所需的輸出或計算由多個命令組成,而且在整個腳本執行過程當中須要屢次,這可能很是有用。函數是使用函數關鍵字定義,後面是用花括號括起來的函數體。如:user_details {}
定義函數方法:
function 函數名{ 函數體(命令) } 函數名() { 函數體(命令) } 函數名() { 函數體(命令) }
[abc@localhost ~]$ vi function.sh #!/bin/bash function user_details { echo "User Name: $(whoami)" echo "User Home: $HOME" } user_details
詳細描述:
function是函數關鍵字,user_details是函數名。
花括號裏邊的是函數體,包括兩個echo命令,在兩個echo以前有縮進,縮進爲1個tab,4個空格。縮進能夠擇本身的縮進方式。
最後的user_details 是在調用函數。
注意:函數定義必須在函數調用以前進行,不然腳本將返回stderr:command not found錯誤。
#!/bin/bash # this bash script is backup a general user's home directory to /tmp/ user=$(whoami) input=/home/$user output=/tmp/${user}_home$(date +%Y-%m-%d_%H%M%S).tar.gz function total_files { find $1 -type f | wc -l } function total_directory { find $1 -type d | wc -l } tar czf $output $input 2> /dev/null echo -n "files to be included:" total_files $input echo -n "directory to be included:" total_directory $input echo "Backup of $input completed!!" echo "Details about the output backup file:" ls -l $output
代碼片斷:
定義tottal_files函數,功能利用function find() { [native code] }和wc命令,來統計 提供給函數調用的目錄的文件數量。
定義total_diretory函數,功能利用function find() { [native code] }和wc命令,來統計 提供給函數調用的目錄的目錄數量。
執行腳本顯示以下:
描述 | 數值比較 | 字符串比較 |
---|---|---|
少於 less than | -lt | < |
大於 greater than | -gt | > |
等於 equal | -eq | = |
不等於 not equal | -ne | != |
小於或等於 | -le | N/A |
大於或等於 | -ge | N/A |
字符串不是空 | N/A | -n |
字符串是空 | N/A | -z |
N/A:表明不可用/不適用
-n $1
:字符串$1不是空的
-z $1
:字符串$1 爲空
當兩個數值比較後,能夠用echo $?
來檢查返回值,來查看結果是True 返回0;結果是False返回爲1。
[abc@localhost ~]$ a=1 [abc@localhost ~]$ b=2 [abc@localhost ~]$ [ $a -lt $b ] [abc@localhost ~]$ echo $? #正確返回0 0 [abc@localhost ~]$ [ $a -gt $b ] [abc@localhost ~]$ echo $? #不正確返回1 1 [abc@localhost ~]$ [ $a -eq $b ] [abc@localhost ~]$ echo $? 1
[abc@localhost ~]$ [ "apple" = "banana" ] [abc@localhost ~]$ echo $? 1 [abc@localhost ~]$ str1="apple" [abc@localhost ~]$ str3="apple" [abc@localhost ~]$ str2="banana" [abc@localhost ~]$ [ $str1 = $str2 ] [abc@localhost ~]$ echo $? 1 [abc@localhost ~]$ [ $str1 = $str3 ] [abc@localhost ~]$ echo $? 0
條件容許程序員根據某些條件或事件在shell腳本中實現決策。
咱們所指的條件語句是:if、then、else。
舉個例子:if num1大於num2,then 就打印num1大於2,else 若是不大於,就打印其餘信息。
[abc@localhost ~]$ vi num.sh #!/bin/bash num1=100 num2=200 if [ $num1 -gt $num2 ];then echo "$num1 greater than num2" else echo "$num1 less than or equal $num2" fi
注意:fi
是關閉if條件塊的關鍵詞;注意中括號兩邊的間距,沒有空間,就不能執行。
[abc@localhost ~]$ chmod +x num.sh [abc@localhost ~]$ ./num.sh 100 less than or equal 200
查看當前目錄下是否有mysql目錄
[abc@localhost ~]$ vi mysql.sh #!/bin/bash directory="./mysql" if [ -d $directory ]; then echo "$directory is exist!!!" else echo "$directory is not exist!" fi
執行結果:
[abc@localhost ~]$ sh mysql.sh ./mysql is not exist! [abc@localhost ~]$ mkdir mysql [abc@localhost ~]$ sh mysql.sh ./mysql is exist!!!
[abc@localhost ~]$ cat nested.sh #!/bin/bash # 這是一個嵌套if else腳本,while循環讓用戶循環選擇字段。 # 定義一個標誌 choise=0 # 定義一個函數,打印用戶可選擇的序號 字段 function p1() { echo "1. BeiJing" echo "2. ShangHai" echo "3. ChangSha" echo "請選擇你喜歡城市的序號[1-3]" } # 當choise爲0的時候就循環 while [ $choise -eq 0 ]; do p1 read choise if [ $choise -eq 1 ]; then echo "你選擇的是:Beijing" else if [ $choise -eq 2 ]; then echo "您的選擇是: ShangHai" else if [ $choise -eq 3 ]; then echo "您的選擇是:ChangSha" else echo 「請輸入合法的字段」 choise=0 fi fi fi done
執行結果:
[abc@localhost ~]$ sh nested.sh 1. BeiJing 2. ShangHai 3. ChangSha 請選擇你喜歡城市的序號[1-3] 1 你選擇的是:Beijing [abc@localhost ~]$ sh nested.sh 1. BeiJing 2. ShangHai 3. ChangSha 請選擇你喜歡城市的序號[1-3] 4 「請輸入合法的字段」 1. BeiJing 2. ShangHai 3. ChangSha 請選擇你喜歡城市的序號[1-3] 3 您的選擇是:ChangSha [abc@localhost ~]$ sh nested.sh 1. BeiJing 2. ShangHai 3. ChangSha 請選擇你喜歡城市的序號[1-3] 2 您的選擇是: ShangHai
[abc@localhost ~]$ cat elif.sh #!/bin/bash # 經過用戶輸入兩個數值,分別賦值給num一、num2,而後來比較大小 read num1 num2 if [ $num1 -eq $num2 ]; then echo "Both values are equal!" elif [ $num1 -gt $num2 ]; then echo "num1 values is greater then num2" else echo "num1 values is less then num2" fi
執行結果:
[abc@localhost ~]$ sh elif.sh 11 22 num1 values is less then num2 [abc@localhost ~]$ sh elif.sh 11 11 Both values are equal! [abc@localhost ~]$ sh elif.sh 6 2 num1 values is greater then num2
執行完tar備份以後,要比較源數據的文件數量和備份後tar包的文件的數量。
#!/bin/bash # this bash script is backup a general user's home directory to /tmp/ user=$(whoami) input=/home/$user output=/tmp/${user}_home$(date +%Y-%m-%d_%H%M%S).tar.gz function total_files { find $1 -type f | wc -l } function total_directory { find $1 -type d | wc -l } function total_archived_directory { tar -tzf $1 | grep /$ |wc -l } function total_archived_files { tar -tzf $1 | grep -v /$ | wc -l } tar czf $output $input 2> /dev/null src_files=$( total_files $input ) src_directory=$( total_directory $input ) arch_files=$( total_archived_files $output ) arch_directory=$( total_archived_directory $output ) echo "Files to be include: $src_files" echo "Directories to be include: $src_directory" echo "Files archived: $arch_files" echo "Directories archived: $arch_directory" if [ $src_files -eq $arch_files ];then echo "Backup of $input completed!!!" echo "Details about the output backup file:" ls -l $output else echo "Backup of $input Failed!!!" fi
指令 | 描述 |
---|---|
-b filename | 塊特殊文件 |
-c filename | 特殊字符文件 |
-d directory name | 檢查目錄是否存在 |
-e filename | 檢查文件是否存在 |
-f filename | 檢查是否存在常規文件,而不是目錄 |
-G filename | 檢查文件是否存在,是否有效組ID |
-g filename | 若是文件存在並設置了組id,則爲true。 |
-k filename | Sticky bit |
-L filename | 符號連接 Symbolic link |
-O filename | 若是文件存在並有效用戶id,則爲true。 |
-r filename | 檢查文件是否可讀 |
-S filename | 檢查文件是否爲socket |
-s filename | 檢查文件大小是否爲非零 |
-u filename | Check if file set-ser-id bit is set |
-w filename | 檢查文件是否可寫 |
-x filename | 檢查文件是否可執行 |
[abc@localhost ~]$ vi file-test.sh #!/bin/bash # this is a test file exist ? yes/no file="./testtest.txt" if [ -e $file ]; then echo "File exists!" else echo "File does not exists" fi
腳本執行結果:
[abc@localhost ~]$ /bin/bash file-test.sh File does not exists [abc@localhost ~]$ touch testtest.txt [abc@localhost ~]$ /bin/bash file-test.sh File exists!
到目前爲止,咱們的備份腳本看起來很棒。咱們能夠計算結果壓縮備份文件中包含的文件和目錄的數量。此外,咱們的腳本還促進了一個健全檢查,以確認全部文件已正確備份。缺點是咱們老是被迫備份當前用戶的目錄。若是腳本足夠靈活,容許系統管理員僅經過將腳本指向主目錄就能夠備份所選系統用戶的主目錄,那就太好了。
當使用bash位置參數時,這是一個至關容易的任務。位置參數經過命令行參數分配,並可在腳本中訪問,如$1, $2...$N
變量。在腳本執行期間,在程序名稱以後提供的任何附加項都被視爲參數,並在腳本執行期間可用。
$、$# 、$*
考慮如下示例:
[abc@localhost ~]$which bash > position.sh [abc@localhost ~]$ vi position.sh #!/usr/bin/bash echo $1 $2 $4 echo $# echo $* [abc@localhost ~]$ /bin/bash position.sh 1 2 3 4 1 2 4 4 1 2 3 4 [abc@localhost ~]$ /bin/bash position.sh one two three four one two four 4 one two three four
腳本詳細:
#!/usr/bin/bash echo $1 $2 $4 echo $# echo $*
第二行表明打印:第一個、第二個、第四個 位置參數
第三行表明打印:$#提供參數的總和
第四行表明打印:$*提供的全部參數
使用位置參數知識,讓咱們如今改進咱們的backup.sh
腳原本接受命令行中的參數。實現讓用戶決定哪一個目錄將被備份。若是用戶在腳本執行期間沒有提交任何參數,默認狀況下,該腳本將備份當前用戶的主目錄。新腳本以下:
#!/bin/bash # this bash script is used to backup a user's home directory if [ -z $1 ];then user=$(whoami) else if [ ! -d "/home/$1" ]; then echo "Requested $1 user home directory doesn't exist!" exit 1 fi user=$1 fi # define default backup directory and tar.gz files input=/home/$user output=/tmp/${user}_home_$(date +%Y-%m-%d_%H%M%S).tar.gz # count the number of source files function total_files { find $1 -type f | wc -l } # count the number of source directory function total_directory { find $1 -type f | wc -l } # count the number of archived files total_archived_files() { tar -tzf $1 | grep /$ | wc -l } # count the number of archived directory total_archived_directory() { tar -tzf $1 | grep -v /$ | wc -l } tar -czf $output $input 2> /dev/null src_files_num=$( total_files $input ) src_directory_num=$( total_directory $input) arch_files_num=$( total_archived_files $output) arch_directory_num=$( total_archived_directory $output) echo "files to be included: $src_files_num" echo "directory to be included: $src_directory_num" echo "files to be included of archived: $arch_files_num" echo "directory to be included of archived: $arch_directory_num" if [ $src_files_num -eq $arch_files_num ]; then echo "Backup of $input complete!!" echo "Deatils about the output backup file:" ls -l $output else echo "Backup of $input Failed!!!" fi
腳本執行結果:
#不加參數執行,默認備份當前用戶主目錄 [abc@localhost ~]$ ./backup.sh files to be included: 21 directory to be included: 21 files to be included of archived: 1 directory to be included of archived: 21 Backup of /home/abc Failed!!! #加參數指定用戶abc,備份abc用戶的主目錄 [abc@localhost ~]$ ./backup.sh abc files to be included: 21 directory to be included: 21 files to be included of archived: 1 directory to be included of archived: 21 Backup of /home/abc Failed!!! #加參數指定用戶aaa,aaa用戶不存在,報錯了。 [abc@localhost ~]$ ./backup.sh aaa Requested aaa user home directory doesn't exist!
到目前爲止,本分腳本功能和可用性已經大大提升,經過位置參數咱們能夠指定備份 某個用戶的主目錄,咱們能夠輕鬆的備份任何用戶目錄。
當咱們須要天天備份多個用戶目錄時,就會變得重複、乏味、費時。
這個時候咱們能夠用循環構造來迭代任何給定數量的任務。
有三種基本循環類型。
for循環用於迭代列表中任意數量的提供項的任何給定代碼。讓咱們從一個簡單的for循環示例開始:
[abc@localhost ~]$ for i in 1 2 3; do echo $i; done 1 2 3
上邊的for循環使用了echo 命令打印因此項目。使用分號容許在當行執行for循環。將上面的for循環變成bash腳本,以下:
[abc@localhost ~]$ vi loop.sh #!/bin/bash for i in 1 2 3; do echo $i done ~
for循環由四個shell保留字段組成:for、in、do、done。
所以,上述代碼能夠理解爲:for
循環in
在列表中的每一項,而後將每一項臨時賦值給變量i,而後do
用echo $i
打印到stdout,直到列表循環完才結束done
。
計算文本里邊每行的字符數量
[abc@localhost ~]$ cat items.txt abc abcd abcdef a [abc@localhost ~]$ for i in $( cat items.txt ); do echo -n $i | wc -c; done 3 4 6 1
while循環在給定的條件下工做。它將繼續執行封閉的代碼。當條件爲true的時候,do
執行代碼,當條件變爲false就終止done
。
[abc@localhost ~]$ vi while.sh #!/bin/bash counter=0 while [ $counter -lt 3 ]; do let counter+=1 echo $counter done
代碼詳解:
定義變量:counter
while定義條件:當變量counter小於3的時候,條件爲true。在每次循環迭代期間,使用let將counter自加1,而後打印變量counter。
done:當條件變成false 結束循環
腳本執行結果:
[abc@localhost ~]$ sh while.sh 1 2 3
until循環和while循環徹底相反的操做。利用until、do、done,循環直到條件從false變成true就結束。
[abc@localhost ~]$ vi until.sh #!/bin/bash counter=6 until [ $counter -lt 3 ]; do let counter-=1 echo $counter done
代碼詳解:
定義變量:counter
until定義條件:當變量counter不小於3的時候,條件爲false。在每次循環迭代期間,使用let將counter自加1,而後打印變量counter。
done:當條件變成true 結束循環
腳本執行結果:
[abc@localhost ~]$ sh until.sh 5 4 3 2
以前的備份腳本每次執行備份一個用戶的目錄。咱們能夠經過位置參數給腳本提供多個用戶,經過for循環去執行備份命令。以下:
#!/bin/bash # this bash script is used to backup one or more user's home directory function backup { if [ ! -d "/home/$1" ]; then echo "resquested $1 user home directory does't exist." exit 1 fi user=$1 input=/home/$user output=/tmp/${user}_home_$(date +%Y-%m-%d_%H%M%S).tar.gz function total_files { find $1 -type f | wc -l } function total_directories { find $1 -type d | wc -l } function total_arch_files { tar -xvf $1 | grep -v /$ | wc -l } function total_arch_directories { tar -xvf $1 | grep /$ | wc -l } tar -czf $output $input 2> /dev/null # count the number of src_files and src_directory src_files=$( total_files $input ) src_directories=$( total_directories $input ) arch_files=$( total_arch_files $output ) arch_directories=$( total_arch_directories $output ) echo "######## $user ########" echo "Src_files to be included: $src_files" echo "Src_directories to be included: $src_directories" echo "Arch_files to be included: $arch_files" echo "Arch_directories to be included: $arch_directories" if [ $src_files -eq $arch_files ]; then echo "--------------------------------------" echo "Backup user:<$user> home completed!!!" echo "Details about the output backup files:" ls -l $output else echo "Backup user:<$user> home Failed!!!" fi } for directory in $*; do backup $directory done;
該腳本最好用root用戶去執行,由於普通用戶備份別的用戶home目錄會存在權限問題。但該腳本並不能備份root的home目錄。腳本執行結果:
[root@localhost ~]# sh loop_backup.sh aaa bbb ccc ######## aaa ######## Src_files to be included: 4 Src_directories to be included: 1 Arch_files to be included: 4 Arch_directories to be included: 1 -------------------------------------- Backup user:<aaa> home completed!!! Details about the output backup files: -rw-r--r-- 1 root root 519 Jul 17 04:11 /tmp/aaa_home_2018-07-17_041134.tar.gz ######## bbb ######## Src_files to be included: 5 Src_directories to be included: 2 Arch_files to be included: 5 Arch_directories to be included: 2 -------------------------------------- Backup user:<bbb> home completed!!! Details about the output backup files: -rw-r--r-- 1 root root 573 Jul 17 04:11 /tmp/bbb_home_2018-07-17_041134.tar.gz ######## ccc ######## Src_files to be included: 6 Src_directories to be included: 3 Arch_files to be included: 6 Arch_directories to be included: 3 -------------------------------------- Backup user:<ccc> home completed!!! Details about the output backup files: -rw-r--r-- 1 root root 606 Jul 17 04:11 /tmp/ccc_home_2018-07-17_041134.tar.gz
select表達式是bash的一種擴展應用,擅長於交互式場合。
語法:
select var in ... ; do break; done
例子:
[abc@localhost ~]$ vi select.sh #!/bin/bash PS3="請選擇你最喜歡城市的序號:" select word in "北京" "上海" "杭州" "長沙"; do echo "您選擇的是:$word" break done
執行結果:
[abc@localhost ~]$ sh select.sh 1) 北京 2) 上海 3) 杭州 4) 長沙 請選擇你最喜歡城市的序號:1 您選擇的是:北京
case語句爲多選擇語句。能夠用case語句來匹配一個值與一個模式,若是匹配成功,執行相匹配的命令。
case語法:
case 值 in 模式1) command1 command2 ... ;; # 兩個分號表明結束 模式2) command1 command2 ... ;; esac
如上:case的值後面必須是in,每一個模式必須以 右括號結束,取值能夠是變量或常數。匹配某一模式後,就會執行模式下的全部命令 直到 ;; 。
取值一旦匹配了某個模式,就不會再去匹配其餘模式。若是沒有匹配到,就會用 * 捕獲該值,再執行後面的命令。
case語句最後要有一個結束標記:esac 。
例子:
[abc@localhost ~]$ cat case.sh #!/bin/bash echo "請輸入你喜歡的城市:" echo "1) 北京" echo "2) 上海" echo "3) 杭州" echo "4) 長沙" read num case $num in 1) echo "你選擇的是北京" echo 1 ;; 2) echo "你選擇的是上海" echo 2 ;; 3) echo 「你選擇的是杭州」 ;; 4) echo "你選擇的是長沙" ;; *) echo "輸入錯誤!請選擇[1-4]城市對應的序號!" ;; esac
執行結果:
[abc@localhost ~]$ sh case.sh 請輸入你喜歡的城市: 1) 北京 2) 上海 3) 杭州 4) 長沙 1 你選擇的是北京 1 [abc@localhost ~]$ sh case.sh 請輸入你喜歡的城市: 1) 北京 2) 上海 3) 杭州 4) 長沙 3 「你選擇的是杭州」 [abc@localhost ~]$ sh case.sh 請輸入你喜歡的城市: 1) 北京 2) 上海 3) 杭州 4) 長沙 5 輸入錯誤!請選擇[1-4]城市對應的序號!
[root@ceshi ~]# vi let.sh #!/bin/bash num1=2 num2=3 let result=num1+num2 echo $result 運行: [root@ceshi ~]# /bin/bash let.sh 5
自加操做 let num1++
自減操做 let num1--
簡寫形式:let no+=10let ; let no-=20
等同於:let no=no+10; let no=no-20
[root@ceshi ~]# vi fangkuohao.sh #!/bin/bash num1=2 num2=3 result=$[$num1+num2] echo $result 運行: [root@ceshi ~]# /bin/bash fangkuohao.sh 5
注:使用方法和let類似,在[]中可使用$前綴
[root@ceshi ~]# vi xiaokuohao.sh #!/bin/bash n1=2 n2=3 result=$((n1+n2)) echo $result
[root@ceshi ~]# expr 2 + 3 5 [root@ceshi ~]# num1=5 [root@ceshi ~]# r=$(expr $num1 + 5) [root@ceshi ~]# echo $num1 5 [root@ceshi ~]# echo $r 10
expr的經常使用運算符
它能夠執行浮點運算和一些高級函數
[root@ceshi ~]# echo "1.25*3" | bc 3.75
設定小數精度(也就是小數點顯示幾位)
scale=2 表明小數點顯示2位
[root@ceshi ~]# echo "scale=2;7/3" | bc 2.33
十進制轉二進制: [root@ceshi ~]# a=192 [root@ceshi ~]# echo "obase=2;$a" |bc 11000000 二進制轉十進制: [root@ceshi ~]# b=11000000 [root@ceshi ~]# echo "obase=10;ibase=2;$b"|bc 192
求2的三次方: [root@ceshi ~]# echo "2^3"|bc 8 求100的平方根 [root@ceshi ~]# echo "sqrt(100)"|bc 10
用於指定在接收到信號後將要採起的動做,常見的用途是在腳本程序被中斷時完成清理工做、忽略ctrl+c。
當腳本在執行的時候,在終端駛入ctrl+c,trap會接收到消息,並執行相關trap命令。以下:
[abc@localhost ~]$ cat traptrap.sh #!/bin/bash # difine bash trap command trap bashtrap INT # clear screen command clear; # define trap function:bashtrap, bashstrap is executed when CTRL-C is pressed; bashtrap() { echo "bash trap detected "CTRL+C" when script is executed. " } # for loop from 1/10 to 10/10 for a in `seq 1 10`; do echo "$a/10 to exit" sleep 1; done echo "exit bash trap example!"
當腳本在執行的時候,在終端輸入ctrl+c,trap到以後會執行bashtrap函數。執行結果以下:
[abc@localhost ~]$ sh traptrap.sh 1/10 to exit 2/10 to exit ^Cbash trap detected CTRL+C when script is executed. 3/10 to exit ^Cbash trap detected CTRL+C when script is executed. 4/10 to exit ^Cbash trap detected CTRL+C when script is executed. 5/10 to exit 6/10 to exit 7/10 to exit ^Cbash trap detected CTRL+C when script is executed. 8/10 to exit 9/10 to exit 10/10 to exit exit bash trap example!
詳見:第四章 數組、關聯數組和別名使用
https://blog.51cto.com/506554897/2114414
[abc@localhost ~]$ vi array.sh #!/bin/bash # 聲明數組array,並賦值3個元素 array=( "Debian linux" "redhat linux" "ubuntu linux") # 得到數組array裏邊有多少個元素 elements=${#array[@]} # 經過for循環數組裏邊的元素的索引,並經過數組索引打印每一個元素 for (( i=0;i<$elements;i++)); do echo ${array[${i}]} done
執行結果:
[abc@localhost ~]$ sh array.sh Debian linux redhat linux ubuntu linux
[abc@localhost ~]$ cat read.sh #!/bin/bash # 這是一個讀取文件每行內容到數組的腳本。 # 聲明一個變量array declare -a array # 用stdin連接文件記錄器10 exec 10<&0 # 將stdin替換爲做爲第一個參數提供的文件。 exec < $1 # 用while循環將文件每行內容做爲一個元素寫入數組 # count用做數組的下標 let count=0 while read line; do echo "line text is: $line" array[$count]=$line ((count++)) done # 打印數組的元素總個數,@和* 這裏是一個意思 都是全部 echo "count the number of array elements: ${#array[@]}" # 打印數組的全部元素 echo "array content is: ${array[*]}" # 從filedescriptor 10恢復stdin; filedescriptor:文件記錄器 # 關閉filedescriptor 10 exec 0<&10 10<&-
declare 聲明變量和顯示變量 詳見:第二十八章 聲明和顯示shell變量:declare命令
執行結果:
[abc@localhost ~]$ cat a.txt welcome to china [abc@localhost ~]$ sh read.sh a.txt line text is: welcome line text is: to line text is: china count the number of array elements: 3 array content is: welcome to china [abc@localhost ~]$ cat b.txt 大母雞 小母雞 母雞 母雞 老母雞 [abc@localhost ~]$ sh read.sh b.txt line text is: 大母雞 小母雞 line text is: 母雞 母雞 line text is: 老母雞 count the number of array elements: 3 array content is: 大母雞 小母雞 母雞 母雞 老母雞
\
反斜槓就是轉義特殊符號。
轉義元字符就是抑制元字符的特殊含義,所以元字符將被bash逐字逐句的閱讀。
語法:\特殊字符
[abc@localhost ~]$ vi escape.sh #!/bin/bash var1="Bash Script" echo "$var1" echo "\$var1"
執行結果:
[abc@localhost ~]$ sh escape.sh Bash Script $var1
bash中的單引號 抑制每一個元字符的特殊含義,元字符將被逐字逐句讀取。
即便單引號被反斜槓轉義,也不可能在兩個單引號中使用另外一單引號。
[abc@localhost ~]$ vi quotes.sh #!/bin/bash var2="Bash Script" echo "$var2" echo '$var2 "$var2"'
執行結果:
[abc@localhost ~]$ sh quotes.sh Bash Script $var2 "$var2"
雙引號將抑制除了 `$ \ `` 之外的每一個元字符的特殊含義。
任何其餘元字符都會被逐字逐句讀取。
在雙引號中可使用單引號。若是須要在雙引號中使用雙引號,可使用"\" 進行轉義。
[abc@localhost ~]$ vi double-quote.sh #!/bin/bash var3="Hello world" echo "$var3" echo "這是一個打招呼的詞語:$var3" echo "這是一個到招呼的詞語: \"$var3\", time is `date +"%Y-%m-%d_%H:%M:%S"` "
執行結果以下:
[abc@localhost ~]$ sh double-quote.sh Hello world 這是一個打招呼的詞語:Hello world 這是一個到招呼的詞語: "Hello world", time is 2018-07-19_16:35:23
ANSI-C :ANSI C是由美國國家標準協會(ANSI)及國際標準化組織(ISO)推出的關於C語言的標準。
在ANSI-C 類型的引用中,用「\」 轉義的字符將按照ANSI-C標準得到特殊的含義。
轉義字符 | 描述 |
---|---|
\a | alert 警報 |
\b | backspace 退格鍵 |
\e | 一個轉義字符 |
\f | form feed 換頁符 |
\n | newline 換行 |
\r | carriage return 回車 |
\t | horizontal tab 水平製表符 |
\v | vertical tab 垂直製表符 |
\\ |
反斜槓 |
\' |
單引號 |
\nnn | 字符的八進制值(見[http:/www.asciitable.com/ASCII表]) |
\xnn | 字符的十六進制值(見[http:/www.asciitable.com/ASCII表]) |
ANSI-C 引用語法:$‘
[abc@localhost ~]$ vi ansic.sh #!/bin/bash echo $'http://www.abc.com\nmai\x40abc.com' [root@docker-2 ~]# vi a.sh #!/bin/bash echo $'http://www.baidu.com\nmail\x40baidu.com'
執行結果:
[abc@localhost ~]$ sh ansic.sh http://www.abc.com mai@abc.com [root@docker-2 ~]# sh a.sh http://www.baidu.com mail@baidu.com
本教程pdf下載地址:http://down.51cto.com/data/2451862 下載內容包含筆者29章節的 shell學習筆記 也可參考shell連接:http://tldp.org/LDP/abs/html/