shell 指令碼如何編寫-致初學者

發表於2023-09-19

一些寫指令碼經驗, 僅供參考, 對於寫 jenkins 指令碼和運維有用

指令碼檔案

#! /bin/bash
# scripts write here 

變數

# 賦值 = 兩邊不能有空格
var=xxx

# 區域性變數; 預設全是全域性變數
local var=xxx

# 引數, 從指令碼外來的引數為  $1, $2, $3 ; 一般在指令碼開始將其重新命名賦值
param1=$1

# 陣列 用空格分開
array=(var1 var2 var3)

# 變數中的變數; 
image=app
appTar=/home/apps/app.tar
image_path=$(eval echo '$'${image}'Tar')  
load_result=`docker load < $image_path`  

# 字串拼接
# shell 中的字串拼接不用任何連線符, 直接寫後面就可以
var1=xx
var2=bbb
var3="${var1}${var2}foo"
echo $var3

輸出

# echo 列印不換行
echo -n "輸出字元"

輸入

# 輸入提示
read -p "提示語: " var 
echo $var

# 輸入陣列, 每個項要用空格分隔 
read -p "input array: " array

for ((i=0; i<${#array[@]}; i++)){
  item=${array[i]}
  echo $item
}

# 輸入目錄, 輸入目錄時可以使用 tab 
read -p "input dir: " -e path 
echo $path

程式控制

if 分支

# if空格[空格<變數>空格==空格<變數>空格];空格then
if [ "x" == "x${version}" ]; then  
    # do if 
else  
    # do else
fi
條件判斷中, 由於 shell 對於 > < 等字元敏感, 所以, 大於, 小於寫成 gt lt 形式

case 分支

case $var in 
"value1")
  # do value1
  ;;
"*")
  # do not catch 
  ;;
esac
case 分支一般用來處理選擇分支程式, 如果輸入項沒有滿足要求, 則最後列印使用說明
usage() {  
    echo "Usage: sh server.sh [start|stop]"  
    exit 1  
}
case "$1" in  
  "start")  
    start  
    ;;  
  "stop")  
    stop  
    ;;  
  "*")  
    usage  
    ;;  
esac

for 迴圈

array=(1 2 3)
for ((i=0; i<${#array[@]}; i++)){
  item=${array[i]}
  echo $item
}
這種 for 迴圈比較符合常規程式語言, 所以我一般喜歡用這個 for 迴圈

用 find 命令查到的檔案, 可以使用 for in 來操作

sqlfiles=`find . -name "*.sql"`
for sqlfile in $sqlfiles  
do
    echo $sqlfile
done

函式

# 函式宣告, 也需要先宣告才能使用
function fun(){
    param1=$1
    param2=$2
    # some scripts  
    result=xxx
    return 1
}

# 函式呼叫
fun "mm" 1

echo $?
echo "fun result is: $result"

shell 中函式的引數和返回值和其它程式中不太一樣

引數: 和 shell 指令碼一樣, 引數名為 $1 $2 $3 ...

返回值: 只能返回數字, 呼叫處使用 $? 接收 表示上條命令的執行結果; 注意: 要立即接收, 這個只能表示上一條命令的執行結果, 不然下一條命令一執行, 這個值就沒了

一般使用全域性變數來傳遞函式的返回值, 因為它的返回值功能實在是太弱了

模組

單獨的功能另啟指令碼來寫, 呼叫另一個指令碼

sh script.sh 

引數: 和調指令碼引數一樣 $1 $2 $3

返回值: 返回值需要使用 export 暴露出來, 呼叫處的指令碼才能訪問到

export var=xxxx

刪除命令注意事項

在寫指令碼的時候, 一定要慎用 rm, 不確定時可以用 mv 命令, 移動到別的地方

# 危險指令, 當 var1 為空時
var1='某個指令執行的結果'
rm -f /$var1

完整的示例

#!/bin/sh  
# 獲取本機 iplocal_ip(){  
  local_ip=`ip add | grep inet | grep -v 127.0.0.1 | grep -v inet6 | awk '{print $2}' | cut -d'/' -f 1  | head -n 1`  
  #echo ">> 獲取本機IP 為: $local_ip"  
  echo $local_ip  
}  
  
## java env  
# export JAVA_HOME=/usr/local/jdk/jdk1.8.0_101  
export JRE_HOME=$JAVA_HOME/jre  
  
# extend lib path  
libpath=sanritoolslib  
  
# 本機 ipip=$(local_ip)  
  
# Java opts  
JAVA_OPTS="-Xms256m -Xmx256m -Dcom.sun.management.jmxremote.port=10086 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=$ip"  
  
echo "JAVA_OPTS:${JAVA_OPTS}"  
  
API_NAME=sanritools  
JAR_NAME=$API_NAME\.jar  
#PID  代表是PID檔案  
PID=$API_NAME\.pid  
  
#使用說明,用來提示輸入引數  
usage() {  
    echo "Usage: sh server.sh [start|stop|restart|status]"  
    exit 1  
}  
  
#檢查程式是否在執行  
is_exist(){  
  pid=`ps -ef|grep $JAR_NAME|grep -v grep|awk '{print $2}' `  
  #如果不存在返回1,存在返回0  
  if [ -z "${pid}" ]; then  
   return 1  
  else  
    return 0  
  fi  
}  
  
#啟動方法  
start(){  
  is_exist  
  if [ $? -eq "0" ]; then  
    echo ">>> ${JAR_NAME} is already running PID=${pid} <<<"  else  
    nohup $JRE_HOME/bin/java -Dloader.path=$libpath $JAVA_OPTS -jar $JAR_NAME >/dev/null 2>&1 &  
    echo $! > $PID  
    echo ">>> start $JAR_NAME successed PID=$! <<<"   fi  
  }  
  
#停止方法  
stop(){  
  #is_exist  
  pidf=$(cat $PID)  
  #echo "$pidf"  
  echo ">>> api PID = $pidf begin kill $pidf <<<"  kill $pidf  
  rm -rf $PID  
  sleep 2  
  is_exist  
  if [ $? -eq "0" ]; then  
    echo ">>> api 2 PID = $pid begin kill -9 $pid  <<<"    kill -9  $pid  
    sleep 2  
    echo ">>> $JAR_NAME process stopped <<<"  else  
    echo ">>> ${JAR_NAME} is not running <<<"  fi  
}  
  
#輸出執行狀態  
status(){  
  is_exist  
  if [ $? -eq "0" ]; then  
    echo ">>> ${JAR_NAME} is running PID is ${pid} <<<"  else  
    echo ">>> ${JAR_NAME} is not running <<<"  fi  
}  
  
#重啟  
restart(){  
  stop  
  start}  
  
#根據輸入引數,選擇執行對應方法,不輸入則執行使用說明  
case "$1" in  
  "start")  
    start  
    ;;  
  "stop")  
    stop  
    ;;  
  "status")  
    status  
    ;;  
  "restart")  
    restart  
    ;;  
  "*")  
    usage  
    ;;  
esac  
exit 0

相關文章