Shell 是 linux 系統下很是實用的工具。經過使用 Shell,能夠提高在 linux 系統下的工做效率。javascript
代碼都在這裏:https://github.com/xiang2017/shell_studyphp
#!/bin/bash # 變量 echo "01_變量.sh" # 變量定義與賦值,等號兩邊不能用空格分開 name=hahahaha echo $name echo 也可使用 {} 輸出: ${name} # 一些特殊變量 test_func() { echo "function name is $FUNCNAME" } test_func echo $HOSTNAME echo $HOSTTYPE echo $MATCHTYPE echo $LANG echo $PWD # echo $PATH unset name echo $name # 只讀變量 readonly R0=100 R0=200 echo $? # 上一條指令是錯誤的,因此 $? 爲非0 # 變量的做用域 # 變量的做用域又叫「命名空間」,相同名的變量能夠在不一樣命名空間定義。 # 在 Linux 系統中,不一樣進程 ID 的 Shell 默認爲不一樣的命名空間 VAR_01=100 function update() { # 在函數內外訪問到的是同一個變量 VAR_01=200 } update echo 變量 VAR_01: $VAR_01 function update02() { # 可使用 local 關鍵字聲明函數內部的局部變量 local VAR_01=300 } update02 echo "local 聲明的本地變量不會影響全局變量,VAR_01: ${VAR_01}" # 子 Shell 不會繼承變量 echo "echo 子 shell 的 VAR_01 爲 \$VAR_01" > tmp.sh bash ./tmp.sh # 導出變量(環境變量),子 Shell 可繼承,至關於子 Shell 啓動時複製了導出的變量 export VAR_01 bash ./tmp.sh # 在子 Shell 中修改 VAR_01 不會影響 rm ./tmp.sh # 刪除 tmp.sh
#!/bin/bash # 轉義 # 跟其餘編程語言裏的轉義同樣,使用轉義符 \ echo \# 使用轉義輸出註釋符號 \# Dollar=123 echo \$Dollar is $Dollar echo 8 \* 8 = 64 # 引用 # Shell 中一共有 4 中引用符,分別是 雙引號,單引號,反引號,轉義符 # "" 雙引號:部分引用,能夠解釋變量 echo "\$Dollar is $Dollar" # 帶不帶雙引號看起來同樣,可是對於輸出空格有區別 VAR="A B C" echo 不帶引號對於連續空格只輸出一個:$VAR echo "帶引號會把全部空格輸出:$VAR" # '' 單引號:全引用,只按照字面意思輸出內容,轉義符也不能用了 echo '$Dollar 在單引號內仍是 $Dollar。' echo '轉義符在單引號內輸出 \,單引號只把內容做爲字面量輸出' echo '轉義符不能用,單引號內不能輸出單引號' # `` 反引號:命令替換,將命令的標準輸出做爲值賦給某個變量 # 命令替換也可使用 $(命令) 的形式 LS=`ls` echo "=== LS ===" echo $LS echo "=== LS ===" LSA=$(ls -a) echo $LSA # $() 支持嵌套 $(echo $(ls) > tmp.sh) TMP=$(cat tmp.sh) echo === tmp === echo $TMP echo === tmp === rm tmp.sh
#!/bin/bash # 運算符 # Shell 的運算符主要有: # 比較運算符(整數比較),字符串運算符(字符串測試),文件操做運算符(用於文件測試),邏輯運算符,算術運算符,位運算符,自增自減等 # 算術運算符:加減乘除餘冪 以及加等,減等,乘等,初等,餘等 A=1 B=2 let "C = $A + $B" # 須要使用 let 關鍵字執行運算 echo $C # 位運算符:左移 右移 按位與 按位或 按位非 按位異或 var1=1 var2=5 let "var = $var1<<2" echo $var let "var = $var1&$var2" echo $var # 按位非就是 -($var+1) let "var = ~8" echo $var # 自增自減,與其餘語言相似,分爲前置和後置的區別 var1=1 echo "var1 is $var1" let "var2=++var1" echo "var2 前置自增 var1,$var2" var1=1 let "var2=var1++" echo "var2 後置自增 var1,$var2" # 其餘算術運算 # 使用 $[] 作運算:$[] 和 $(()) 相似,可用於簡單的算術運算 echo '$[1+1]' is $[1+1] echo '$[5 ** 2]' is $[5 ** 2] # 使用 expr 作運算:使用 expr 要求操做數和操做符之間用空格分開,不然會被當成字符串 expr 1+1 expr 1 + 1 expr 2 \* 2 # 特殊字符運算符須要轉義 # 算術擴展: $((算術表達式)) echo $((2*(1+1))) # 使用 bc 作運算 # 前面介紹的運算只能基於整數,若是想要計算高精度小數,可使用 Linux 下的 bc 工具。 # bc 是一款高精度計算語言,支持順序執行,判斷,循環,函數等,下面是一個簡單的例子 NUM1=1.2 NUM2=2.3 SUM=$(echo "$NUM1+$NUM2" | bc) echo $SUM # 你也能夠直接在命令行下輸入 bc,而後回車進入 bc 命令行模式
#!/bin/bash # 特殊字符 # 通配符 # 通配符用於模式匹配,常見的通配符有 *、? 和用 [] 括起來的字符序列。 # 例如:a* 能夠匹配以 a 開頭的任意長度的字符串,可是不能包含 點號和斜線號 # 因此 a* 不能匹配 abc.txt # ? 能夠匹配任意單個字符 # [] 表示能夠匹配其中的任意一個,好比 [abc] 能夠匹配a或者b或者c # [] 中能夠用 - 表示起止。好比 [a-z] 匹配全部小寫字母 # *? 在 [] 表示普通字符,沒有通配功效 # 引號 # 02_轉義和引用.sh 中介紹過,主要有單引號,雙引號,反引號 # 註釋符號 # 大括號 # 大括號 {} 在 Shell 中的用法不少 # 1. 變量擴展 ${PWD} # 2. 通配符擴展 # 3. 語句塊 # 通配符擴展的例子: touch file_{A,B} ls . | grep file rm file_A rm file_B # 其餘 # 位置參數 # $0: 腳本名自己 # $1,$2... 腳本的第一個參數,第二個參數... # $# 變量總數 # $* $@ 顯示全部參數 # $? 前一個命令的退出的返回值 echo $? # 正常退出,結果爲 0 rm qweqweqweqwe echo $? # 出現錯誤時,結果爲 非0 # $! 最後一個後臺進程的 ID 號
#!/bin/bash # 測試:程序運行過程當中常常須要根據實際狀況執行特定的命令, # 好比,判斷某個文件是否存在,若是不存在,可能須要先建立該文件 # ls tmp.sh # echo $? # 測試結構 # 1. test expression 使用 test 指令 # 2. [expression] 使用 [] # 文件測試 # 1. test file_operator FILE # 2. [file_operator FILE] test -e tmp.sh echo $? # 不存在,上一個指令結果爲 1 [ -e tmp.sh ] echo $? # 文件測試符,文件不存在時,均返回假 # -b FILE 當文件存在且是塊文件時,返回真,不然爲假 # -c FILE 當文件存在且是設備文件時,返回真,不然爲假 # -d FILE 測試文件是否爲目錄 # -e FILE 測試文件或目錄是否存在 # -f FILE 測試文件是否爲普通文件 # -x FILE 判斷文件是否爲可執行文件 # -w FILE 判斷文件可寫 # -r FILE 判斷文件可讀 # -l FILE 判斷是否爲連接文件 # -p FILE 判斷是否爲管道文件 # -s FILE 判斷文件存在且大小不爲 0 # -S FILE 判斷是否爲 socket 文件 # -g FILE 判斷文件是否設置了 SGID # -u FILE 判斷文件是否設置了 SUID # -k FILE 判斷文件是否設置了 sticky 屬性 # -G FILE 判斷文件屬於有效的用戶組 # -O FILE 判斷文件屬於有效的用戶 # FILE1 -nt FILE2 FILE1 比 FILE2 新時返回真 # FILE1 -ot FILE2 FILE1 比 FILE2 舊時返回真 # 字符串測試 # 主要包括 等於、不等於、大於、小於、是否爲空 # -z string 爲空時返回真 echo "字符串測試" [ -z "" ] echo '[ -z "" ]' $? # 結果 0,表示爲真 # -n string 非空時返回真 [ -n "aaa" ] echo '[ -n "aaa" ]' $? [ "string1" = "string2" ] echo '[ "string1" = "string2" ]' $? [ "string1" != "string2" ] echo '[ "string1" != "string2" ]' $? [ "string1" > "string2" ] echo '[ "string1" > "string2" ]' $? [ "string1" < "string2" ] echo '[ "string1" < "string2" ]' $? # 整數比較 # -eq 意 相等 # -gt 意 > # -lt 意 < # -ge 意 >= # -le 意 <= # -ne 意 != [ 1 -eq 2 ] echo '[ 1 -eq 2 ]' $? [ 1 -gt 2 ] echo '[ 1 -gt 2 ]' $? [ 1 -lt 2 ] echo '[ 1 -lt 2 ]' $? [ 1 -ge 2 ] echo '[ 1 -ge 2 ]' $? [ 1 -le 2 ] echo '[ 1 -le 2 ]' $? [ 1 -ne 2 ] echo '[ 1 -ne 2 ]' $? # 邏輯測試符與邏輯運算符 # ! expression 取反 # expression -a expression 同爲真,結果爲真 # expression -o expression 只有有一個爲真,結果爲真 touch tmp.sh [ ! -e tmp.sh ] echo '[ ! -e tmp.sh ]' $? [ -e tmp.sh -a -e tmp1.sh ] echo '[ -e tmp.sh -a -e tmp1.sh ]' $? [ -e tmp.sh -o -e tmp1.sh ] echo '[ -e tmp.sh -o -e tmp1.sh ]' $? # -a -o 能夠用 && 和 || 替代,不過寫法上會有區別 [ -e tmp.sh ] && [ -e tmp1.sh ] echo '[ -e tmp.sh ] && [ -e tmp1.sh ]' $? [ -e tmp.sh ] || [ -e tmp1.sh ] echo '[ -e tmp.sh ] || [ -e tmp1.sh ]' $? rm tmp.sh rm string2
#!/bin/bash # bash 的判斷與循環與其餘語言相似,有 if else elif case # if 判斷結構 # if expression; then # command # elif expression; then # command # else # command # fi if [ ! -e tmp.sh ]; then echo "tmp.sh 不存在,建立它" touch tmp.sh if [ -e tmp.sh ]; then echo "tmp.sh 建立好了" else echo "tmp.sh 建立失敗" fi else echo "tmp.sh 存在,刪了它" rm tmp.sh fi # case 判斷結構 # case VAR in # var1) command ;; # var2) command ;; # ... # *) command ;; # esac read -p "請輸入數字:" NUM case $NUM in 1) echo "輸入爲 1" ;; 2) echo "輸入爲 2" ;; *) echo "輸入爲 其餘" ;; esac rm tmp.sh
#!/bin/bash # 循環 # Shell 的循環主要有 for、while、until、select 幾種 # for 循環 # 帶列表的 for 循環: # for VAR in (list) # do # command # done for NUMBER in 1 2 3 4 5 do echo $NUMBER done fruits="apple banana orange" for FRUIT in ${fruits} do echo $FRUIT done # 循環數字時可使用 {a..b} 表示從 a 循環到 b for N in {2..10} do echo $N done # 其中 {2..10} 能夠用 seq 命令替換 echo "echo with seq:" for N in $(seq 2 10) do echo $N done # seq 命令能夠加 「步長」 for N in $(seq 1 2 20) do echo $N done # 能夠看出,for in 後面的內容能夠是任意命令的標準輸出 # 好比,咱們能夠輸出當前目錄下的全部帶 sh 的文件 for VAR in $(ls | grep sh) do echo $VAR done # 若是 for 後面沒有 in ,則至關因而 in $@ # 你能夠執行 bash 07_循環.sh a b c 試一試 for VAR do echo $VAR done # 類 C 的 for 循環 # for ((exp1; exp2; exp3)) # do # command # done for ((i=0, j=100; i < 10; i ++)) do echo $i $j done # while 循環 # 語法以下: # while expression # do # command # done # while ((1)) 會無限循環 COUNT=0 while [ $COUNT -lt 5 ] do echo $COUNT let "COUNT++" done # while 按行讀取文件 echo "john 30 boy sue 20 girl" > tmp.txt while read LINE do NAME=`echo $LINE | awk '{print $1}'` AGE=`echo $LINE | awk '{print $2}'` SEX=`echo $LINE | awk '{print $3}'` echo $NAME $AGE $SEX done < tmp.txt # 輸入重定向 rm tmp.txt # until 循環 # until 與 while 相似,區別在於 until 判斷爲 否,會繼續循環,而 while 判斷爲 真,才繼續循環 # until ((0)) 會無限循環 COUNT=0 until [ $COUNT -gt 5 ] do echo $COUNT let "COUNT++" done # select 循環 # select 是一種菜單式的循環方式,語法結構與 for 類似,每次循環的值由用戶選擇 echo "choose your menu:" select MENU in "apple" "banana" "orange" "exit" do echo "you choose $MENU" if [[ $MENU = "exit" ]] then break else echo "choose again" fi done # 循環控制,break continue,與其餘編程語言一致
#!/bin/bash # 函數 # 函數的定義 # function FUNCTION_NAME() { # command # } # 省略 function 關鍵字 # FUNCTION_NAME() { # command # } function func1 { echo 1 } func2() { echo 2 } # 函數調用 func1 func2 # 函數返回值 func3 () { echo '請輸入函數的返回值:' read N return $N } func3 echo "上個函數的返回值是" $? # 使用 $? 獲取上一條指令的返回值 # 函數參數 # 與腳本的參數使用一致 func4 () { echo "第一個參數 $1" echo "第二個參數 $2" echo "全部參數 $@" echo "參數數量 $#" } func4 a b c # 使用 set 能夠指定位置的腳本(或函數)參數值 func5() { set q w e echo "參數1 $1" echo "全部參數: $@" } func5 # 移動位置參數:在 Shell 中可使用 shift 命令把參數左移一位 func6() { while [ $# -gt 0 ] do echo current \$1 is $1 shift done } func6 q w e r t # 實現一個 pow 函數 pow() { let "r=$1**$2" return $r } pow 2 5 echo $?
#!/bin/bash # 重定向 # 重定向是指將本來由標準輸入輸出的內容,改成輸入輸出的其餘文件或設備 # 系統在啓動一個進程時,會爲該進程打開三個文件: # 標準輸入(stdin)、標準輸出(stdout)、標準錯誤(stderr) # 分別用文件標識符 0、一、2 標識 # 若是要爲進程打開其餘的輸入輸出,須要從證書 3 開始標識 # 默認狀況下,標準輸入爲鍵盤,標準輸出和標準錯誤爲顯示器 # 常見的 IO 重定向符號 # > 標準輸出覆蓋重定向,將命令的標準輸出重定向到其餘文件中,會直接覆蓋原文件內容 # >> 標準輸出追加劇定向,將命令的標準輸出重定向到其餘文件中,不會覆蓋文件,會在文件後面追加 # >& 標識輸出重定向,講一個標識的輸出重定向到另外一個標識的輸入 # < 標準輸入重定向,命名將從指定文件中讀取輸入,而不是從鍵盤中讀取輸入 # | 管道,從一個命令中讀取輸出,做爲另外一個命令的輸入 # 輸出重定向 # 把本來標準輸出到屏幕的內容,重定向到 tmp.txt 文件中 echo "result1" > tmp.txt cat tmp.txt echo "result2" > tmp.txt cat tmp.txt # 輸出追加 echo "輸出追加:" echo "result3" >> tmp.txt echo "result3" >> tmp.txt echo "result3" >> tmp.txt cat tmp.txt rm tmp.txt # 標識輸出重定向 echo "未重定向標準錯誤,會直接輸出到頁面" # 制定一個不存在的命令 adhfafahdfakdf > tmp.txt echo "tmp.txt:" `cat tmp.txt` rm tmp.txt echo "重定向標準錯誤到標準輸出,會輸出到文件中" asiiaodfuoaf > tmp.txt 2>&1 echo "tmp.txt:" `cat tmp.txt` # 標準輸入重定向 echo "標準輸入重定向:" while read Line do echo $Line done < tmp.txt # 管道 # 獲取 .sh 文件的名稱 ls | grep .sh | cut -f1 -d'.' # 使用 exec # exec 是 Shell 的內建命令,執行這個命令時,系統不會啓動新的 Shell,而是用被執行的命令替換當前的 Shell 進程 # 所以,在執行完 exec 的命令後,該 Shell 進程將會主動退出 # 例如:執行 exec ls ,後續的其餘命令將不會執行。你也能夠直接打開 Shell,執行 exec ls 試試 # 此外,exec 還能夠用於 I/O 重定向。 # exec < file 將 file 文件中的內容做爲 exec 的標準輸入 # exec > file 將 file 文件做爲標準輸出 # exec 3<file 指定文件標識符 # exec 3<&- 關閉文件標識符 # exec 3>file 將寫入文件標識符的內容寫入到指定文件(輸出重定向) # exec 4<&3 建立文件標識符4,4是3的拷貝 (相似標識輸出重定向 2>&1) # 注:不一樣的 shell 環境可能會有所差異,好比我在 mac 的 zsh 下就不能正常使用 exec 重定向 # Here Document # here doc 又稱爲 此處文檔,用於在命令或腳本中按行輸入文本。 # 格式爲 command << delimiter # delimiter 是用於標註結束的分隔符 # 示例: # 你能夠在命令行下輸入 sort << END 試試 # 你能夠在命令行下輸入 cat > tmp.txt << END 試試 cat << EOF > tmp.txt 1 2 3 EOF cat tmp.txt rm tmp.txt
#!/bin/bash # 數組 # bash 只支持一維數組 # 定義數組 declare -a mArray mArray[0]="nihao" mArray[1]=2 # 定義時賦值,數組的元素用空格分開,其餘字符會被當成值,好比 "php", 會被當成 php, declare -a mArray=("php" "python" 123) # 數組取值,須要用 ${數組名[索引]} 語法 echo ${mArray[0]} echo ${mArray[1]} echo ${mArray[2]} # 使用 @ * 能夠索引所有元素 # @ 獲得以空格分開的元素值 # * 獲得整個字符串 echo ${mArray[@]} echo ${mArray[*]} # 數組長度 echo "數組長度是 ${#mArray[@]}" echo "數組長度是 ${#mArray[*]}" # 數組截取 # 能夠獲取子數組,下面示例爲獲取數組的第 一、2 下標位置的元素 echo ${mArray[@]: 1:2} # 能夠獲取數組中某個元素的若干字符,下面示例爲獲取數組中第二個元素的 從0開始 3個字符 echo ${mArray[1]: 0:3} # 合併數組 Front=("javascript" "typescript") # 數組聲明也能夠忽略 declear -a Conn=(${mArray[@]} ${Front[@]}) echo ${Conn[@]} echo ${#Conn[@]} # 合併獲得數組的長度 # 替換元素 mArray=(${mArray[@] /123/"java"}) echo ${mArray[@]} # 取消數組或元素 unset mArray[1] echo "取消下標爲 1 的元素後,數組爲:${mArray[@]},數組長度爲 ${#mArray[@]}" # 須要注意的是,數組的 1 位置的元素變爲了空,而不是後面的元素向前移動 echo "數組 1 位置的元素爲 ${mArray[1]}, 2 位置的元素爲 ${mArray[2]}"
#!/bin/bash # 字符處理 # 管道 # 從一個命令中讀取輸出,做爲另外一個命令的輸入 # 示例 # ls | grep .sh | cut -f1 -d'.' # grep # grep 是基於行的文本搜索工具,該命令經常使用的參數有: # grep [-ivnc] '須要匹配的字符' 文件名 # -i 不區分大小寫 # -c 統計包含匹配的行數 # -n 輸出行號 # -v 反向匹配 # 其中 '須要匹配的字符' 支持正則表達式模式 grep -in 'func' 01_變量.sh # sort # sort 能夠對無序的數據進行排序 # sort [-ntkr] 文件名 # -n 採起數字排序 # -t 指定分隔符 # -k 指定第幾列 # -r 反向排序 # 示例 使用空格分開每行,按第二列進行排序 echo "3 1 3 1 2 4 5 3 2 1 2 4 5 3 4 2 3 4" | sort -t ' ' -k 2 # uniq # 使用 uniq 能夠刪除重複內容 echo "123 123 ab ab" | uniq # cut 截取文本 # cut -f指定的列 -d'分隔符' # 指定的列能夠用逗號分隔開,或者使用範圍 echo "jhon 10 boy class1 lili 12 girl class2" | cut -f2-4 -d ' ' # tr 作文本轉換 # tr '原字符' '目標字符' 其中原字符與目標字符一一對應 head -n 5 01_變量.sh | tr '[a-z]' '[A-Z]' # paste 進行文本合併 # paste 會把文本按行合併。 # paste -d echo "1 2 3" > tmp1.txt echo "a b c" > tmp2.txt paste -d: tmp1.txt tmp2.txt > tmp.txt cat tmp.txt # split 分割大文件 # split -l lines file dist_file # 示例 split -l 5 01_變量.sh split_file ls | grep split_file rm split_file* # sed 與 awk # ... # 若是現有工具不能知足你對字符串處理的需求,那就去了解一下 sed 和 awk 命令。 rm tmp*
#!/bin/bash USER=root PASSWORD=root # 使用 -e 執行 databases=`mysql -u$USER -p$PASSWORD -e"show databases"` for db in $databases do echo "Tables in $db:" # 使用 here doc 執行代碼塊 mysql -u$USER -p$PASSWORD << EOF use $db; show tables; EOF # 也可使用輸入重定向 # mysql -u$USER 0pPASSWORD < select.sql done