在公司項目的開發過程當中,須要編寫shell腳本去處理一個業務,在編寫過程當中發現自身對shell腳本的知識不夠完善,顧整理一下,本文章主要內容來自菜鳥教程 , 也添加了一些知識點html
看完這邊文章應該就能夠獨立完成大部分腳本得編寫node
shell腳本?
在說什麼是shell腳本以前,先說說什麼是shell。mysql
shell是外殼的意思,就是操做系統的外殼。咱們能夠經過shell命令來操做和控制操做系統,好比Linux中的Shell命令就包括ls、cd、pwd等等。總結來講,Shell是一個命令解釋器,它經過接受用戶輸入的Shell命令來啓動、暫停、中止程序的運行或對計算機進行控制。linux
shell 是一個應用程序,它鏈接了用戶和 Linux 內核,讓用戶可以更加高效、安全、低成本地使用 Linux 內核,這就是 Shell 的本質。算法
shell 自己並非內核的一部分,它只是站在內核的基礎上編寫的一個應用程序。sql
那麼什麼是shell腳本呢?shell
shell腳本就是由Shell命令組成的執行文件,將一些命令整合到一個文件中,進行處理業務邏輯,腳本不用編譯便可運行。它經過解釋器解釋運行,因此速度相對來講比較慢。數據庫
shell腳本中最重要的就是對shell命令的使用與組合,再使用shell腳本支持的一些語言特性,完成想要的功能。編程
博主全部文章首發在微信公衆號:【匠心Java】bootstrap
【匠心Java】公衆號分享工做中涉及到的技術知識,主要分享數據庫相關和Java技術乾貨(JVM+併發+全鏈路優化);涉及計算機網絡、數據結構與算法、linux等編程知識;
「# 」開頭的就是註釋,被編譯器忽略
變量類型
運行shell時,會同時存在三種變量:
變量操做
字符串變量
1)單引號
var='test'
,只能原樣輸出,變量無效2)雙引號
var="my name is ${name}"
,變量有效3)拼接字符串
4)獲取字符串長度
5)提取子字符串
數組
bash只支持一維數組,不支持多維數組
算數運算
數字關係運算符
關係運算符只支持數字,不支持字符串,除非字符串的值是數字。
下面假定變量 a 爲 10,變量 b 爲 20
-le : 檢測左邊的數是否小於等於右邊的,若是是,則返回 true。 [ $a -le $b ] 返回 true。
字符串運算符
下表列出了經常使用的字符串運算符,假定變量 a 爲 "abc",變量 b 爲 "efg":
$ :檢測字符串是否爲空,不爲空返回 true。 [ $a ] 返回 true。
布爾運算符
下表列出了經常使用的布爾運算符,假定變量 a 爲 10,變量 b 爲 20:
邏輯運算符
如下介紹 Shell 的邏輯運算符,假定變量 a 爲 10,變量 b 爲 20:
文件運算符
命令替換
命令替換與變量替換差很少,都是用來重組命令行的,先完成引號裏的命令行,而後將其結果替換出來,再重組成新的命令行。
執行命令:
for file in \s /etc\ 或 for file in $(ls /etc) 循環中使用
`dirname \$0` 獲取腳本文件所在的目錄
path=$(cd `dirname $0`;pwd) : 獲取腳本當前所在目錄,而且執行cd命令到達該目錄,使用pwd獲取路徑並賦值到path變量
算術運算
邏輯判斷
echo
僅用於字符串的輸出,沒有使用printf做爲輸出的移植性好,建議使用printf
printf
printf 不會像 echo 自動添加換行符,咱們能夠手動添加 \n
無大括號,直接以空格分隔
printf format-string [arguments...]
其中(format-string: 格式控制字符串、arguments: 參數列表)printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
%-10s
: 指一個寬度爲10個字符(-表示左對齊,沒有則表示右對齊),任何字符都會被顯示在10個字符寬的字符內,若是不足則自動以空格填充,超過也會將內容所有顯示出來。%-4.2f
:指格式化爲小數,寬度爲4個字符,其中.2
指保留2位小數。和Java、PHP等語言不同,sh的流程控制不可爲空,即if或者else的大括號中無任何語句
if else
if condition then command1 command2 ... commandN fi
if condition then command1 command2 ... commandN else command fi
if condition1 then command1 elif condition2 then command2 else commandN fi
for
for var in item1 item2 ... itemN do command1 command2 ... commandN done
while
while condition do command done
while : do command done
until
until 循環執行一系列命令直至條件爲 true 時中止。
until 循環與 while 循環在處理方式上恰好相反。
until condition do command done
case
Shell case語句爲多選擇語句。能夠用case語句匹配一個值與一個模式,若是匹配成功,執行相匹配的命令。
case須要一個esac(就是case反過來)做爲結束標記,每一個case分支用右圓括號,用兩個分號表示break,其中「;;」不是跳出循環,是不在去匹配下面的模式
case語句格式以下:
case 值 in 模式1) command1 command2 ... commandN ;; 模式2) command1 command2 ... commandN ;; esac
跳出循環
能夠帶function fun() 定義,也能夠直接fun() 定義,不帶任何參數。
[ function ] funname() { action; [return int;] }
funWithParam(){ echo "第一個參數爲 $1 !" echo "第二個參數爲 $2 !" echo "第十個參數爲 $10 !" echo "第十個參數爲 ${10} !" echo "第十一個參數爲 ${11} !" echo "參數總數有 $# 個!" echo "做爲一個字符串輸出全部參數 $* !"} funWithParam 1 2 3 4 5 6 7 8 9 34 73 echo $? \# 判斷執行是否成功
BIN=\
abs_path``語句,獲取的是函數體內全部的echo、printf輸出<u>組合成的一個字符串</u> abs_path() { SOURCE="${BASH_SOURCE[0]}" while [ -h "$SOURCE" ]; do DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" SOURCE="$(readlink "$SOURCE")" [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" done echo "test" echo "$( cd -P "$( dirname "$SOURCE" )" && pwd )" # 此函數的兩個echo輸出會組合成一個字符串做爲下述BIN的值 }
BIN=abs_path
# BIN賦值函數返回值,若是沒有return,則函數中全部的echo、printf輸出組合成一個字符串傳入BIN
path=${BIN}/nodetool # 可直接使用
#### 輸入輸出重定向 通常狀況下,每一個 Unix/Linux 命令運行時都會打開三個文件: * 標準輸入文件(stdin):stdin的文件描述符爲0,Unix程序默認從stdin讀取數據。 * 標準輸出文件(stdout):stdout 的文件描述符爲1,Unix程序默認向stdout輸出數據。 * 標準錯誤文件(stderr):stderr的文件描述符爲2,Unix程序會向stderr流中寫入錯誤信息。 默認狀況下,command > file 將 stdout 重定向到 file,command < file 將stdin 重定向到 file。 若是但願執行某個命令,但又不但願在屏幕上顯示輸出結果,那麼能夠將輸出重定向到 /dev/null: **輸入重定向** 1. bash.sh < file : 將腳本的輸入重定向到file,由file提供參數 **輸出重定向** 1. bash.sh > file : 將腳本的輸出數據重定向到file中,覆蓋數據 2. bash.sh >> file : 將腳本的輸出數據重定向到file中,追加數據 3. command >> file 2>&1 : 將 stdout 和 stderr 合併後重定向到 file #### 讀取外部輸入 命令:`read arg` (腳本讀取外部輸入並賦值到變量上) 在shell腳本執行到上述命令時,中止腳本執行並等待外部輸入,將外部輸入賦值到arg變量上,繼續執行腳本 #### 文件引用 引用其餘的文件以後,可使用其變量、函數等等,至關於將引用的文件包含進了當前文件 兩種方式: 1. **.** file_path\file_name 2. **source** file_path\file_name #### 顏色標識 ```shell printf "\033[32m SUCCESS: yay \033[0m\n"; printf "\033[33m WARNING: hmm \033[0m\n"; printf "\033[31m ERROR: fubar \033[0m\n";
輸出結果:
在shell中爲避免一個語句過長,可使用「\」進行換行
使用「\」換行,在腳本執行過程當中仍是當作一行一個語句執行,不一樣於enter直接換行
注意:\ 前添加一個空格 。 \ 後無空格直接換行。
/mysql/bin/mysql \ -h test_host -P 000 \ -u test_user -ptest_password ;
下面案例爲登陸mysql,並選擇操做數據庫,以後進行導入數據
/mysql/mysql/bin/mysql \ -h test_host -P 000 \ -u test_user -ptest_password \ -e"use test_database; source data_faile; " # -e 表明執行sql語句
-u 用戶名
-p 用戶密碼
-h 服務器ip地址
-D 鏈接的數據庫
-N 不輸出列信息
-B 使用tab鍵 代替 分隔符
-e 執行的SQL語句退出腳本
命令:
exit
在退出腳本時使用不一樣的錯誤碼,這樣能夠根據錯誤碼來判斷髮生了什麼錯誤。
在絕大多數 shell 腳本中,exit 0 表示執行成功,exit 1 表示發生錯誤。
對錯誤與錯誤碼進行一對一的映射,這樣有助於腳本調試。
命令:set -e 或者 set +e
set -e表示從當前位置開始,若是出現任何錯誤都將觸發exit。相反,set +e表示無論出現任何錯誤繼續執行腳本。
若是腳本是有狀態的(每一個後續步驟都依賴前一個步驟),那麼請使用set -e,在腳本出現錯誤時當即退出腳本。
若是要求全部命令都要執行完(不多會這樣),那麼就使用set +e。
檢查是否有語法錯誤-n
:bash -n script_name.sh
使用下面的命令來執行並調試 Shell 腳本-x
:bash -x script_name.sh
調試count_odd_number.sh 程序案例:
#!/usr/bin.env bash # 用於計算數組中奇數的和 # @author liyangyang # @time 2019/09/17 sum=0 for num in 1 2 3 4;do re=${num}%2 if (( ${re} == 1 ));then sum=$[${sum}+${num}] fi done echo ${sum}
bash -n count_odd_number.sh
bash -x count_odd_number.sh
+ sum=0 + for num in 1 2 3 4 + re=1%2 + (( 1%2 == 1 )) + sum=1 + for num in 1 2 3 4 + re=2%2 + (( 2%2 == 1 )) + for num in 1 2 3 4 + re=3%2 + (( 3%2 == 1 )) + sum=4 + for num in 1 2 3 4 + re=4%2 + (( 4%2 == 1 )) + echo 4 4
其中的輸出顯示了程序執行的每一步,經過觀察程序執行的步驟是否知足預期從而達到調試的效果
帶有 + 表示的是 Shell 調試器的輸出,不帶 + 表示程序的輸出。
這是es(ElasticSearch)官方啓動服務的腳本,看可不能夠理解吧~
#!/usr/bin/env bash # CONTROLLING STARTUP: # # This script relies on a few environment variables to determine startup # behavior, those variables are: # # ES_PATH_CONF -- Path to config directory # ES_JAVA_OPTS -- External Java Opts on top of the defaults set # # Optionally, exact memory values can be set using the `ES_JAVA_OPTS`. Note that # the Xms and Xmx lines in the JVM options file must be commented out. Example # values are "512m", and "10g". # # ES_JAVA_OPTS="-Xms8g -Xmx8g" ./bin/elasticsearch source "`dirname "$0"`"/elasticsearch-env parse_jvm_options() { if [ -f "$1" ]; then echo "`grep "^-" "$1" | tr '\n' ' '`" fi } ES_JVM_OPTIONS="$ES_PATH_CONF"/jvm.options ES_JAVA_OPTS="`parse_jvm_options "$ES_JVM_OPTIONS"` $ES_JAVA_OPTS" # manual parsing to find out, if process should be detached if ! echo $* | grep -E '(^-d |-d$| -d |--daemonize$|--daemonize )' > /dev/null; then exec \ "$JAVA" \ $ES_JAVA_OPTS \ -Des.path.home="$ES_HOME" \ -Des.path.conf="$ES_PATH_CONF" \ -cp "$ES_CLASSPATH" \ org.elasticsearch.bootstrap.Elasticsearch \ "$@" else exec \ "$JAVA" \ $ES_JAVA_OPTS \ -Des.path.home="$ES_HOME" \ -Des.path.conf="$ES_PATH_CONF" \ -cp "$ES_CLASSPATH" \ org.elasticsearch.bootstrap.Elasticsearch \ "$@" \ <&- & retval=$? pid=$! [ $retval -eq 0 ] || exit $retval if [ ! -z "$ES_STARTUP_SLEEP_TIME" ]; then sleep $ES_STARTUP_SLEEP_TIME fi if ! ps -p $pid > /dev/null ; then exit 1 fi exit 0 fi exit $?
若是轉載此博文,請附上本文連接
若是感受這篇文章對您有所幫助,請點擊一下「喜歡」或者「關注」博主,您的喜歡和關注將是我前進的最大動力!謝謝你們~