# Linux_RH134_01_Shell Shell是一個命令行解釋器(直譯式程式設言),它為用戶提供了一個向Linux內核發送請求以便運行程序的界面系統級程序,用戶可以用Shell來啟動、挂起、停止甚至是編寫一些程序。 參考:[學習 Shell Scripts-鳥哥的 Linux 私房菜](http://linux.vbird.org/linux_basic/0340bashshell-scripts.php) ![[Linux_RH124_19_Shell_01.png]] ## 🐧Hello World ### Shell腳本 腳本`#!/bin/bash`開頭,以指定直譯器,若沒寫Red Hat默默為`#!/bin/sh` ```shell #!/bin/bash echo "Hello World~!!" # 輸出指向stderr echo "ERROR: A ERRPR MESSAGE." >&2 ``` ### Shell執行 - 前提條件:必須有執行的權限 - 無法在當前資料夾直接輸入要執行的shell文件,因為無指定絕對路徑或相對路徑時,Linux只會找${PATH}下是否有Shell Script ```bash [mickey@mickey Documents]$ hallo.sh bash: hallo.sh: command not found... [mickey@mickey Documents]$ pwd /home/mickey/Documents [mickey@mickey Documents]$ ${PATH} -bash: /home/mickey/.local/bin:/home/mickey/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin ``` - 執行shell的方法: 1. 將shell腳本放至${PATH}中的目錄底下(不建議做法) 2. 將shell腳本的目錄加入${PATH}中(不建議做法) 3. 輸入絕對路徑 ```bash [mickey@mickey Documents]$ $(pwd)/hallo.sh Hello World~!! ``` 4. 輸入相對路徑 ```bash [mickey@mickey Documents]$ ./hallo.sh Hello World~!! ``` ### 注釋 - 單行注釋 ```shell #單行注釋 ``` - 多行注釋 ```shell :<<! 多行注釋 ! ``` ### 轉義控制字元 如:$、#…等 1. 使用`\控制字元` ```bash [root@localhost ~]# echo \$HOME = $HOME $HOME = /root ``` 2. `'控制字元'`使裡面的文字轉義,但`"控制字元"`無法將裡面的文字轉義 ```bash [root@localhost ~]# echo '$HOME' = $HOME $HOME = /root [root@localhost ~]# echo "$HOME" = $HOME /root = /root ``` ## 🐧讀取控制台輸入 `read` `-p`,指定讀取值時的提示符(print) `-t`,指定讀取值時等待的時間(秒),若沒有在時間內輸入就不再等待 ```shell #read read -p "請輸入num01值" NUM01 echo "剛剛輸入的num01值為:$NUM01" read -p "請輸入num02、num03值" -t 3 NUM02 NUM03 echo "剛剛輸入的num02、num03值為:$NUM02 $NUM03" ``` ```bash [root@localhost testShell]# ./05_ShellRead 請輸入num01值56 剛剛輸入的num01值為:56 請輸入num02值剛剛輸入的num02值為:14 67 剛剛輸入的num02、num03值為:14 67 ``` ## 🐧變量 - 變量分為: 1. 系統變量 2. shell變量:作用域只在這個Shell(登入~登出也是一個Shell) - 變量命名規則: 1. 變量名可由字母、數字和下劃線組成,但不能以數字開頭 2. 變量名一般習慣為大寫 - `set`,顯示當前shell中所有變量 ```bash [root@localhost testShell]# set | more ABRT_DEBUG_LOG=/dev/null BASH=/bin/bash BASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:pr ogcomp:promptvars:sourcepath ``` ### 變量調用 - 調用參數雖然可以使用`$變數名`,但建議使用`${變數名}`,以免有非預期錯誤 ```shell #!/bin/bash #調用系統變量 echo "PATH=$PATH" echo "user=$USER" ``` ### 聲明變量 - 注意=兩邊不可以有空格 ```shell #!/bin/bash #定義變量 var=100 echo "var=$var" unset var echo "var=$var" ``` ```bash [root@localhost testShell]# ./01_firstShell var=100 var= ``` - 在.sh的聲明的方式一樣,但需注意Shell變數作用域只在此次Shell中,而用戶登入作業系統說到底也是執行Shell,也就是說用戶登出後Shell變數就無效 ```bash [root@localhost ~]# KEY=value ``` ```bash [root@localhost ~]# export TEST_KEY=test value [root@localhost ~]# echo ${TEST_KEY} test ``` ### 釋放變量 - 靜態變量,靜態變量不可以釋放 ```shell #!/bin/bash #靜態變量,不可撒銷 readonly static=200 echo "static=$static" unset static echo "static=$static" ``` ```bash [root@localhost testShell]# ./01_firstShell static=200 ./01_firstShell: line 19: unset: static: cannot unset: readonly variable static=200 ``` - 指令行釋放變量 ```bash [mickey@localhost Documents]$ test="string" [mickey@localhost Documents]$ echo ${test} string [mickey@localhost Documents]$ unset test [mickey@localhost Documents]$ echo ${test} ``` ### 命令行結果為變量 - `'命令'`,聲明指令變量 - `$(命令)`,聲明指令變量 ```shell #!/bin/bash #將命令返回值賦給變量 LS_STR01=`ls -la` echo "LS_STR01=$LS_STR01" LS_STR02=$(ls -la) echo "LS_STR02=$LS_STR02" ``` ```bash [root@localhost testShell]# ./01_firstShell LS_STR01=總計 4 drwxr-xr-x. 2 root root 27 1月 23 10:37 . drwxr-xr-x. 4 root root 175 1月 23 09:50 .. -rwxr--r--. 1 root root 389 1月 23 10:37 01_firstShell LS_STR02=總計 4 drwxr-xr-x. 2 root root 27 1月 23 10:37 . drwxr-xr-x. 4 root root 175 1月 23 09:50 .. -rwxr--r--. 1 root root 389 1月 23 10:37 01_firstShell ``` - `unalias <變量>`,釋放指令變量 ```bash [mickey@localhost Documents]$ unalias test [mickey@localhost Documents]$ test [mickey@localhost Documents]$ ``` ### 環境變量 - 查看所有環境變數 ```bash [mickey@localhost Documents]$ env LANG=en_US_UTF-8 HISTCONTROL=ignoredups (以下省略) ``` - 環境變量路徑:/etc/profile ```bash [root@localhost testShell]# vim /etc/profile ``` - `export 變量名=變量值`,設置環境變量 ```shell #設置環境變量 JAVA_HOME=/opt/jdk1.8.212 export JAVA_HOME ``` ```bash [root@localhost testShell]# echo $JAVA_HOME [root@localhost testShell]# source /etc/profile [root@localhost testShell]# echo $JAVA_HOME /opt/jdk1.8.212 ``` ### 位置參數變量 當執行shell腳時,若希望獲取命令行的參數信息,就可以使用到位置參數變量(類似於java中的main參數),如:`./myShell.sh 100 200` 1. `$n`,n為數字,`$0`代表命令本身,`$1`~`$9`代表第一到第九個參數,第十以上的參數如`$W(12)` 2. `$@`,代表命令行中所有的參數,不過`$@`把每個參數區分對待 3. `$*`,代表命令行中所有的參數 ```shell #位置參數 echo "命令本身=$0" echo "第一個參數=$1" echo "顯示所有參數(分開)=$@" echo "顯示所有參數(一起)=$*" ``` ```bash [root@localhost testShell]# ./01_firstShell 10 20 30 命令本身=./01_firstShell 第一個參數=10 顯示所有參數(分開)=10 20 30 顯示所有參數(一起)=10 20 30 ``` ### 預定義變量 就是shell設計者事先已經定義好的變量,可以直接在shell腳本中使用 1. `$$`,當前進程號(PID) 2. `$!`,後台運行的最後一個進程的進程號(PID) 3. `$?`,最後一次執行的命令的返回狀態,若這個變量值為0,證明上一個命令正確執行;反正若不為0(具體是哪個數,由命令自己來決定),則證明上一個命令執行不正確 ```shell #!/bin/bash #預定義變量 echo "當前進程號=$$" ./01_firstShell 10 20 30 & echo "最後的進程號=$!" echo "執行的值=$?" ``` ```bash [root@localhost testShell]# ./02_ShellVar 當前進程號=16753 最後的進程號=16754 執行的值=0 (以下略) ``` ## 🐧運算符 ```shell #!/bin/bash #運算符 RESULT_01=$(((2 + 3) * 4)) echo "result_01=$RESULT_01" #推薦方式 RESULT_02=$[(2 + 3) * 4] echo "result_02=$RESULT_02" TEMP=`expr 2 + 3` RESULT_03=`expr $TEMP \* 4` echo "result_03=$RESULT_03" ``` ```bash [root@localhost testShell]# ./02_ShellVar result_01=20 result_02=20 result_03=20 ``` ## 🐧條件判斷 - 兩個整數比較 1. `=`,字符串比較 2. `lt`,小於 3. `le`,小於等於 4. `eq`,等於 5. `gt`,大於 6. `ge`,大於等於 7. `ne`,不等於 - 按照文件權限進行判斷 1. `-r`,有讀的權限 2. `-w`,有寫的權限 3. `-x`,有執行的權限 - 按照文件類型進行判斷 1. `-f`,文件存在并且是一個常規的文件 2. `-e`,文件存在 3. `-d`,文件存在并且是一個目錄 ### 判斷命令執行結果 - `$?`,用於判斷前面的命令執行是否成功,回傳直0~255 1. 0 --> 成功 2. !=0 --> 失敗 ```bash [mickey@mickey Documents]$ ping -c3 192.168.11.111 PING 192.168.11.111 (192.168.11.111) 56(84) bytes of data. --- 192.168.11.111 ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 65ms [mickey@mickey Documents]$ echo $? 1 [mickey@mickey Documents]$ ls ./hallo.sh ./hallo.sh [mickey@mickey Documents]$ echo $? 0 ``` ### if ... then ... `if [ condition ] then fi` 注意:condition前後要有空格 ```shell #!/bin/bash #if if [ "ok" = "ok" ] then echo "ok equal ok" fi if [ 25 -gt 20 ] then echo "25 > 20" fi if [ -e "./03_ShellIf" ] then echo "./03_ShellIf 存在" fi ``` ```bash [root@localhost testShell]# ./03_ShellIf ok equal ok 25 > 20 ./03_ShellIf 存在 ``` ### if ... then elif ... then ... `if [ condition ] then elif [ condition ] then fi` ```shell #if else if [ $1 -ge 60 ] then echo "$1 為及格分" elif [ $1 -lt 60 ] then echo "$1 不及格!" fi ``` ```bash [root@localhost testShell]# ./03_ShellIf 65 ok equal ok 25 > 20 ./03_ShellIf 存在 65 為及格分 ``` ### case ```shell #case case $1 in "1") echo "周一" ;; "2") echo "周二" ;; "3") echo "周三" ;; *) echo "其他" ;; esac ``` ```bash [root@localhost testShell]# ./03_ShellIf 2 周二 ``` ## 🐧循環 ### for ```shell #!/bin/bash #host1 host2 host3 #host{1,2,3} for VAR in host{1..3} do echo ${VAR} done ``` - 也可使用`seq`指令結果來循環 - `seq 1 5`,輸出1~5 - `seq 2 2 10`,輸出2~10且間隔為2的數字(2、4、6、8、10) ```shell #!/bin/bash for EVEN in $(seq 2 2 10) do echo ${EVEN} done ``` ```shell #!/bin/bash #for for i in "$*" do echo "num : $i" done echo "==========" for i in "$@" do echo "num : $i" done echo "==========" #從1加總到100 SUM=0 for((i=1;i<=100;i++)) do SUM=$[$SUM + $i] done echo "sum = $SUM" ``` 可以看出`$*`和`$@`的區別 ```bash [root@localhost testShell]# ./04_ShellFor 10 20 30 40 num : 10 20 30 40 ========== num : 10 num : 20 num : 30 num : 40 ========== sum = 5050 ``` ### while ```shell #!/bin/bash #while SUM=0 TEMP=0 while [ $TEMP -le $1 ] do SUM=$[$SUM + $TEMP] TEMP=$[$TEMP + 1] done echo "sum = $SUM" ``` ```bash [root@localhost testShell]# ./04_ShellFor 100 while sum = 5050 ``` ## 🐧函數 shell和其他編程語言一樣,有系統函數,也可以自定義函數 ### 系統函數 - basename,返回文件名 - dirname,返回路徑 ```bash [root@localhost 下載]# basename /root/下載/testJdk.java testJdk.java [root@localhost 下載]# basename testJdk.java .java testJdk [root@localhost 下載]# dirname /root/下載/testJdk.java /root/下載 ``` ### 自定義函數 ```shell #自定義函數 function getSum(){ SUM=$[$NUM01 + $NUM02] echo "總和為 $SUM" } read -p "輸入NUM01:" NUM01 read -p "輸入NUM02:" NUM02 #調用function getSum $NUM02 $NUM02 ``` ```bash [root@localhost testShell]# ./06_ShellFunc 輸入NUM01:6 輸入NUM02:18 總和為 24 ```