還記得當年被 bat
支配的恐懼。比起 shell
腳本寫 bat
腳本真的很費勁。java
既然你能搞明白 java
js
等這些高級語言,弄明白 shell
也是很簡單的。學會簡單的語法,再看看 tomcat
和 nacos
等你熟悉的應用中的腳本,學學別人的技巧,差很少就入門了,對於開發來講,足夠用了。算法
主要內容:spring
在線運行 shell,爲了效率仍是本身整個虛擬機吧。shell
編寫腳本的時候,可使用 vs code
,安裝相應的插件shell-format
,能夠進行語法提示和格式化。centos
寫腳本的時候必定要定義腳本的解析器,否則會出現怪問題。最好給系統內部的解析器同樣。tomcat
個人系統使用的 bash
解析,我寫的定義了 #!/bin/sh
解析腳本。安全
我調用 openssl
算法來計算路徑的 md5
怎麼都不正確。最後發現是解析器定義的不同。springboot
#!/bin/sh
#!/bin/bash
sudo cat /etc/shells
能夠查看系統的解析器。bash
運行 echo ${SHELL}
能夠查看系統默認解析器。微信
個人系統是 Centos
默認 bash
解析。
# 打印出來 /bin/bash echo ${SHELL}
使用 #
來註釋一行內容。
echo
echo
經常使用作打印一段話到顯示器。咱們能夠經過重定向,將內容保存到文件中去。
MY_CONTENT="12124" \ echo "${MY_CONTENT}打印內容到文件" > a.txt
當咱們在控制檯輸入多行命令的時候,可使用 \
來連接命令。
變量的引用使用 $MY_CONTENT
和 ${MY_CONTENT}
是相同的。我習慣與用後者,安全,避免 $MY_CONTENTaaa
這樣的錯誤,我寫成${MY_CONTENT}aaa
就不會有問題。
MY_CONTENT="12124" \ echo "打印內容爲:${MY_CONTENT}" # 打印內容爲:12124
MY_CONTENT="12124" \ echo '打印內容爲:${MY_CONTENT}' # 打印內容爲:${MY_CONTENT}
<font color=red>單引號不會進行變量的替換。</font>
定義變量很簡單,直接符合 java 和 js 的變量規則就好了。一般不指定類型的話,定義都是字符串類型的數據,儘管沒有單雙引號。我習慣用常量的方式定義變量。
A=111
有的時候咱們須要變量的引用。定義了變量 A
,在 A
中引用 B
。
#!/bin/bash BB="張攀欽" AA="${BB}-mflyyou" echo "${AA}-456"
有的時候還想將命令的運行結果賦值給變量。
好比,我想用 pwd
獲取當前路徑再賦值 A
。
#!/bin/bash # 或者 BASE_DIR=`pwd` BASE_DIR=$(pwd) echo "當前路徑爲:${BASE_DIR}"
還有一些變量咱們想讓其在子進程中訪問到。好比我在 a
腳本中定義的 BASE_DIR
,而我在 a
中運行 b
腳本,b
腳本也能夠訪問到 BASE_DIR
;
export BASE_DIR=`cd $(dirname $0)/..; pwd`
特殊變量是已經有特殊意義的變量,可讓咱們能夠獲取一些參數。
變量 | 描述 | 例子 |
---|---|---|
$0 | 當前腳本名稱 | |
$n | 傳給腳本的參數,$1 表示第一個參數 | |
$$ | 當前 shell 的進程 id | |
$? | 上個命令的退出狀態或函數返回值,0 表示正常,其他值異常。建議大於 0 表示異常 | |
$# | 傳給腳本或函數的參數個數 |
error.log
中的內容以下。
#!/bin/bash echo "當前腳本名稱 \$0: $0" echo "傳遞給腳本的第一個參數 \$1: $1" echo "當前 shell 的 pid \$\$: $$" echo "上個命令執行的返回值 \$?:$?" echo "傳遞給腳本的個數 \$#:$#" # 睡眠 6 秒 sleep 6
[parallels@centos-7 ~]$ sh error.log canshu1 當前腳本名稱 $0: error.log 傳遞給腳本的第一個參數 $1: canshu1 當前 shell 的 pid $$: 14952 上個命令執行的返回值 $?:0 傳遞給腳本的個數 $#:1 [parallels@centos-7 ~]$
操做符 | 描述 |
---|---|
-e | 判斷是否文件存在,存在返回 true。 |
-f | 判斷文件是不是一個普通文件,文件不存在返回 false。文件存在返回 true。 |
-d | 判斷路徑是不是一個目錄,不存在返回 false。是目錄且存在返回 true。 |
-r | 文件是否可讀 (指運行這個測試命令的用戶的讀權限) |
-w | 文件是否可寫 (指運行這個測試命令的用戶的寫權限) |
-x | 文件是否可執行 (指運行這個測試命令的用戶的執行權限) |
# ; 與 then 之間須要有空格 if [ ! -f "${BASE_DIR}/logs/start.out" ]; then echo "文件存在" else echo "文件不存在" fi
假定變量 a 爲 10,變量 b 爲 20:
運算符 | 說明 | 舉例 |
---|---|---|
! | 非運算,表達式爲 true 則返回 false,不然返回 true。 | [ ! false ] 返回 true。 |
-o | 或運算,有一個表達式爲 true 則返回 true。 | [ $a -lt 20 -o $b -gt 100 ] <br/>返回 true。 |
-a | 與運算,兩個表達式都爲 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] <br/>返回 false。 |
如下介紹 Shell 的邏輯運算符,[[]] 使用。假定變量 a 爲 10,變量 b 爲 20:
運算符 | 說明 | 舉例 | ||||
---|---|---|---|---|---|---|
&& | 邏輯的 AND | [[ $a -lt 100 && $b -gt 100 ]] <br/>返回 false | ||||
\ | \ | 邏輯的 OR | [[ $a -lt 100 \ | \ | $b -gt 100 ]] <br/>返回 true |
#!/bin/bash a=10 b=20 if [[ $a -lt 100 && $b -gt 100 ]] then echo "返回 true" else echo "返回 false" fi if [[ $a -lt 100 || $b -gt 100 ]] then echo "返回 true" else echo "返回 false" fi
返回 false 返回 true
下表列出了經常使用的 字符串
運算符,假定變量 a 爲 "abc",變量 b 爲 "efg":
運算符 | 說明 | 舉例 |
---|---|---|
= | 檢測兩個字符串是否相等,相等返回 true。 | [ ${a} = ${b} ] <br/>返回 false。 |
!= | 檢測兩個字符串是否相等,不相等返回 true。 | [ ${a} != ${b} ] <br/>返回 true。 |
< | 小於,依照ASCII字符排列順序,注意"<"字符在[ ] 結構裏須要轉義 | if [[ 「${a}" < 「${b}" ]] if [ 「${a}" \< 「${b}" ] |
> | 大於,依照ASCII字符排列順序,注意">"字符在[ ] 結構裏須要轉義. | if [[ 「${a}" > 「${b}" ]] if [ 「${a}" > 「${b}" ] |
-z | 檢測字符串長度是否爲0,爲0返回 true。 | [ -z 「${a}「 ] <br/>返回 false。 |
-n | 檢測字符串長度是否爲0,不爲0返回 true。 | [ -n "$a" ] <br/>返回 true。 |
#!/bin/bash a=e1 b=e2 # 比較的時候加上一個字符混合,更安全 if [ "${a}x" == "${b}x" ]; then echo "${a} == ${b}: a 等於 b" else echo "${a} == ${b}: a 不等於 b" fi if [ "${a}" \> "${b}" ]; then echo '大於' else echo "小於" fi if [[ "${a}" > "${b}" ]]; then echo '大於' else echo "小於" fi
下面這些比較符只能比較 數字
或者 數字字符串
,比較非數字會報錯。
比較操做符 | 描述 | 例子 |
---|---|---|
-eq |
等於 | if [ 3 -eq "3" ] 爲 true |
-ne |
不等於 | if [ "$a" -ne "$b" ] |
-gt |
大於 | if [ "$a" -gt "$b" ] |
-ge |
大於等於 | if [ "$a" -ge "$b" ] |
-lt |
小於 | if [ "$a" -lt "$b" ] |
-le |
小於等於 | if [ "$a" -le "$b" ] |
$(()) 能夠用於數字運算。
運算操做符 | 描述 | 例子 |
---|---|---|
+ | 加號 | echo $((2+2)) |
- | 減號 | |
/ | 除號 | |
* | 乘號 | |
** | 求冪 | |
% | 求模 |
變量 | 描述 | 例子 |
---|---|---|
$0 | 當前腳本名稱 | |
$n | 傳給腳本的參數,$1 表示第一個參數 | |
$$ | 當前 shell 的進程 id | |
$? | 上個命令的退出狀態或函數返回值,0 表示正常,其他值異常。建議大於 0 表示異常 | |
$# | 傳給腳本或函數的參數個數 |
f2() { # 聲明局部變量 local loc_val=23 echo "傳給函數的第一個值爲: $1" return "22" } f2 aaa # 將上個命令 f2 aaa 的返回結果拿到賦值給 code code=$(($?)) echo "執行 f2 的返回值爲 ${code}"
# ; 與 then 之間須要有空格 if [ ! -f "${BASE_DIR}/logs/start.out" ]; then echo "文件存在" else echo "文件不存在" fi
語法比較簡單沒有什麼可說的。
strs="Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto" for planet in ${strs}; do echo ${planet} # 每一個行星被單獨打印在一行上. done
語法比較簡單沒有什麼可說的。
#!/bin/bash count=1 while [ ${count} -le 5 ]; do echo "Loop # ${count}" # count 自增 count=$(( ${count} + 1 )) # ((count++)) done
相似 java
中的 switch 語法。
#!/bin/bash fn() { case "$1" in # 匹配 a 或 c "a" | "c") echo "輸入參數爲 $1 " ;; "b") echo "輸入參數2爲 2 " ;; # 匹配其它 *) echo "輸入其餘" ;; esac } fn a1
select
仍是比較有用的,有的時候咱們須要用戶選擇須要執行的命令,
#!/bin/bash Operations=("start" "stop" "restart") # 輸入提示 PS3="Please input the number of operation :" select operation in ${Operations[@]}; do case ${operation} in "start") echo "執行 start 操做。" break ;; "stop") echo "執行 stop 操做。" break ;; "restart") echo "執行 restart 操做。" break ;; *) echo "輸入錯誤,請從新輸入..." ;; esac done
運行上述腳本的以後,而後你輸入 1
,會執行 start
操做。很方便,不須要用戶輸入參數了。
1) start 2) stop 3) restart Please input the number of operation :
參考了
nacos
的腳本目錄和編寫。
#!/bin/sh # 設置 springboot 啓動的 jar 包 JAR_NAME="proximab-server" # 設置 jvm 配置信息 JAVA_OPT="-server -Xms1g -Xmx1g -Xmn512m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m" # 設置 gc 日誌相關 JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof" # # 只須要考慮修改以上參數就行 # # 判斷是否配置 JAVA_HOME if [ -z "${JAVA_HOME}" ]; then echo "please set JAVA_HOME"; exit 1; fi # 設置執行的 java 路徑 export JAVA="${JAVA_HOME}/bin/java" # 設置項目的根路徑 export BASE_DIR=`cd $(dirname $0)/..; pwd` # 設置配置文件位置,而且自定義本身的配置文件位置 DEFAULT_SEARCH_LOCATIONS="classpath:/,classpath:/config/,file:./,file:./config/" CUSTOM_SEARCH_LOCATIONS=${DEFAULT_SEARCH_LOCATIONS},file:${BASE_DIR}/conf/ # 設置啓動的配置文件 JAVA_OPT="-jar ${JAVA_OPT} ${BASE_DIR}/lib/${JAR_NAME}.jar --spring.config.location=${CUSTOM_SEARCH_LOCATIONS}" JAVA_OPT="${JAVA_OPT} --logging.config=${BASE_DIR}/conf/logback-spring.xml" # 配置日誌文件生成的位置 JAVA_OPT="${JAVA_OPT} --logging.log-path=${BASE_DIR}/logs" # 項目日誌位置 if [ ! -d "${BASE_DIR}/logs" ]; then mkdir ${BASE_DIR}/logs fi # 啓動時輸出啓動的日誌 if [ ! -f "${BASE_DIR}/logs/start.out" ]; then touch "${BASE_DIR}/logs/start.out" fi # 將啓動的 java 相關的配置信息打印到日誌文件中 echo "${JAVA} ${JAVA_OPT} ${BASE_DIR}/lib/${JAR_NAME}" > ${BASE_DIR}/logs/start.out 2>&1 & # 將錯誤日誌 和 正常輸入日誌重定向到 start.out 中去 nohup ${JAVA} ${JAVA_OPT} >> ${BASE_DIR}/logs/start.out 2>&1 & echo "${JAR_NAME} is starting,you can check the ${BASE_DIR}/logs/start.out"
#!/bin/sh # 設置 jar 名稱 JAR_NAME="proximab-server" # # 只須要考慮修改以上參數就行 # # 設置項目的根路徑 export BASE_DIR=`cd $(dirname $0)/..; pwd` PID=`ps -ef | grep -i "${JAR_NAME}.jar" | grep java | grep -v grep | awk '{print $2}'` if [ -z "$PID" ] ; then echo "No ${JAR_NAME} running." exit 1; fi echo "The ${JAR_NAME} is running ,PID is (${PID}) ..." kill ${PID} if [ $? != 0 ]; then echo "kill ${JAR_NAME} fail" exit 1; fi echo "kill ${JAR_NAME} is OK, PID (${PID} shutdown )"
本文由 張攀欽的博客 創做。 可自由轉載、引用,但需署名做者且註明文章出處。如轉載至微信公衆號,請在文末添加做者公衆號二維碼。微信公衆號名稱:Mflyyou