Shell
Overview
Hello World
TIP
shell 文件以 .sh
为后缀
使用 bash main.sh
命令执行 shell 脚本
可定义输入参数进行终端交互
: bash main.sh start -l
#!声明bash解释器的位置 #!/bin/bash
, 因为可能会有多个bash版本, 如果升级了bash版本后可设置为 #!/usr/bin/env bash
hello.sh
#!/bin/bash
echo "Hello World!"
Variable
WARNING
- 区分大小写
- 赋值
=
前后不能有空格
变量定义
# 方式一: 直接初始化变量值
name="john"
# 方式二: 通过命令获取并设置变量值
export CURPATH="$(cd .. && pwd)"
count=$(ps -ef | grep -c "ssh")
# 方式三: 读取终端输入参数
read -t 20 -p "enter version >>> " version
变量使用
# 方式一:"$p"
# 使用变量
"$name" "$CURPATH"
# 控制台输入参数
"$#" "$1" "$2"
# 方式二: $p
$CURPATH
# 方式三: ${p}
${p} ${#}
变量的操作
# 只读(不可更改)
readonly name
# 删除
unset name
变量类型
- 环境变量
- 局部变量
- shell变量
示例
basePath=$(cd public && pwd)
echo ${basePath} # /Users/coulsonzero/Documents/web/public
控制台输入参数
TIP
从终端传递参数作用:
- 进行
终端交互
- 设置
可执行权限
$0 # sh文件名(路径)
$# # 所有从终端传递到shell脚本的参数的数
$1 $2 $3 # 输出参数
输入参数示例
# bash | sh
$ bash push.sh dev # $#: 2, #0: "push.sh", $1: "dev"
$ bash push.sh tag -d # $#: 3, $0: "push.sh", $1: "tag", $2="-d"
输入参数数量
# 判断输入参数数量 > 1 ?
if [ $# -ge 1 ]; then
# statement
else
# statement
fi
输入参数值
# 判断第二个输入参数是否为'-l'
if [[ "$2" == "-l" ]]; then
# statement
# 判断第二个输入参数是否为空 -z 相当于 ! -n
elif [[ -z $2 ]]; then
# statement
else
echo "undefined the second argument"
fi
string
"hello shell !" # 初始化
"hello $name" # 字符串格式化
${#name} # 长度
${#name:1:4} # 子串切片
`expr index "$name" io` # 查找字符i或o在字符串中的索引
array
arr=("apple", "pie", "pear")
arr[0]="orange" # arr[i]设置值
${arr[i]} # 读取数组值
${arr[@]} # 读取数组所有元素
${#arr[@]} # 数组长度
${#arr[*]} # 数组长度
Comment
# This is a single-line comment.
:<<EOF
This is a milt-line comment
EOF
:<<'
This is a milt-line comment also
'
:<<!
This is a milt-line comment also
!
Input & Output
input
# -t 等待时间(秒), -p 提示输入
read -p "Enter name: " name
read -t 30 -p "Enter name: " name
output
echo "Hello World!"
# 字符串格式化输出
echo "hello $name"
# 换行输出
echo -n "please enter your name: "
printf "Input a character: " # 定义输出前缀
printf "\nletter\n"
Symbols
# && 命令顺序执行
cd test && pwd
# | 管道 (连结上个指令的标准输出,做为下个指令的标准输入)
who | wc -l
operators
&& || !
# ==
-eq
# !=
-ne
# >
-gt
# <
-lt
# >=
-ge
# <=
-le
If Statement
# 写法一
if [ ]; then
# statement(s)
elif [ ]; then
# statement(s)
elif [ ]; then
# statement(s)
else
# statement(s)
fi
# 写法二
if [ ]
then
# statement(s)
elif [ ]
then
# statement(s)
elif [ ]
then
# statement(s)
else
# statement(s)
fi
# 写法二
if [ ]; then echo "a"
elif [ ]; then echo "b"
elif [ ]; then echo "c"
else echo "other"
fi
Tips
# [ ]中间需要空格隔开!
# ==
if [ "$p" = "--l" ]
# !=
if [ "$p" != "--l" ]
# 长度不为0 (not null)
if [ -n "$p" ]
# 长度为0 (null)
if [ -z "$p" ] # ! -n "$p"
if [ ! -f run.bash ]
其他写法
# ==
if [[ $p == "--l" ]]
# -z
if [[ ! -n "$p" ]]
# [[ ]] 里面可以直接使用 &&
if [[ && ]]
if [ ] && [ ]
示例
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
Case Statement
case可以使用通配符,写起来更简洁明了,但是不能使用-z之类的判断!
case "$1" in
"dev" ) bash dev-push.sh ;;
"master") bash master-push.sh ;;
"both" ) bash dev-push.sh && bash master-push.sh ;;
"tag" ) main ;;
* ) echo "not input argument" ;;
esac
示例
case $str in
[a-zA-Z] ) echo "字母" ;;
[0-99999]) echo "数字" ;;
[,.?!] ) echo "符号" ;;
* ) echo "其他" ;;
esac
For Loop
for i in "$*"; do
echo $i
done
While Loop
i=1
while(( $i<=5 )); do
echo $i
let "int++"
done
break and continue
while :
do
echo -n "输入 1 到 5 之间的数字:"
read num
case $num in
1|2|3|4|5) echo "你输入的数字为 $num!"
;;
*) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
continue echo "游戏结束" # break
;;
esac
done
Function
function main() {
echo "Hello"
}
# 启动函数必须置于顶部
main
执行 Bash shell 脚本
# 执行shell文件
sh deploy.sh
bash deploy.sh
# 刷新
source shellFile.sh
自定义 shell 交互命令
$ sh ./start.sh stop
> "close"
$ sh start.sh start
> "running"
$ sh start.sh deploy
> "deploy无任何操作"
#!/bin/bash
if [ ${#} -ge 1 ]
then
case $1 in
"start") echo "running" ;;
"stop" ) echo "close" ;;
* ) echo "$1无任何操作" ;;
esac
else
echo "
[基础命令]
1) start: 启动
2) stop : 停止进程
示例:bash main.sh start
"
fi
exit
# 直接退出shell脚本, 后续命令不再执行
exit 0 # success
exit 1 # failure: 非0
示例
push.sh
#! /bin/bash
set -e
echo '>>> ===== starting push... ===== <<<'
git add . && git status
# shellcheck disable=SC2162
read -t 60 -p "[commit] >>> " commit_msg
if [ "$commit_msg" == "" ]; then
git reset
echo "[dev] You haven't entered any comments !"
exit 1
else
git commit -m "[commit]: $commit_msg"
git pull origin main
git push origin main
exit 0
fi
echo '>>> ===== ending push... ===== <<<'
golang项目push
golang项目发布
#! /bin/bash
export CUR="shell"
# shellcheck disable=SC2120
function main() {
if [ "$2" = "-d" ]; then # 判断第二个输入参数为'-d' ?
bash tag-delete.sh
elif [ -z "$2" ]; then # 判断第二个输入参数为空 ?
bash tag-release.sh
else # 只有一个输入参数
echo 'undefined the second argument '
fi
exit 0
}
# shellcheck disable=SC2164
cd $CUR
# 判断输入参数数量 > 1 ?
if [ ${#} -ge 1 ]; then
case "$1" in
"dev" ) bash dev-push.sh ;;
"master") bash master-push.sh ;;
"both" ) bash dev-push.sh && bash master-push.sh ;;
"tag" ) main ;;
*) echo "not input argument" ;;
esac
else
echo "
[Bash基础命令]:
1) dev : 推送dev
2) master : 推送master
3) both : 同时推送dev与master
4) tag : 推送tag
5) tag -d : 删除tag
命令示例: sh push.sh dev
"
fi
SprintBoot部署
SpringBoot 部署示例
#!/usr/bin/env bash
#可变参数变量
languageType="javac" #支持 java,javac,netcore 发布
#参数值由pom文件传递
baseZipName="${package-name}-${activeProfile}" #压缩包名称 publish-test.zip的publish
packageName="${package-name}" #命令启动包名 xx.jar的xx
mainclass="${boot-main}" #java -cp启动时,指定main入口类;命令:java -cp conf;lib\*.jar;${packageName}.jar ${mainclass}
#例子
# baseZipName="publish-test" #压缩包名称 publish-test.zip的publish
# packageName="publish" #命令启动包名 publish.jar的xx
#固定变量
basePath=$(cd `dirname $0`/; pwd)
baseZipPath="${basePath}/${baseZipName}.zip" #压缩包路径
baseDirPath="${basePath}" #解压部署磁盘路径
pid= #进程pid
#解压
function shenniu_unzip()
{
echo "解压---------------------------------------------"
echo "压缩包路径:${baseZipPath}"
if [ ! `find ${baseZipPath}` ]
then
echo "不存在压缩包:${baseZipPath}"
else
echo "解压磁盘路径:${baseDirPath}/${baseZipName}"
echo "开始解压..."
#解压命令
unzip -od ${baseDirPath}/${baseZipName} ${baseZipPath}
#设置执行权限
chmod +x ${baseDirPath}/${baseZipName}/${packageName}
echo "解压完成。"
fi
}
#检测pid
function getPid()
{
echo "检测状态---------------------------------------------"
pid=`ps -ef | grep -n ${packageName} | grep -v grep | awk '{print $2}'`
if [ ${pid} ]
then
echo "运行pid:${pid}"
else
echo "未运行"
fi
}
#启动程序
function start()
{
#启动前,先停止之前的
stop
if [ ${pid} ]
then
echo "停止程序失败,无法启动"
else
echo "启动程序---------------------------------------------"
#选择语言类型
read -p "输入程序类型(java,javac,netcore),下一步按回车键(默认:${languageType}):" read_languageType
if [ ${read_languageType} ]
then
languageType=${read_languageType}
fi
echo "选择程序类型:${languageType}"
#进入运行包目录
cd ${baseDirPath}/${baseZipName}
#分类启动
if [ "${languageType}" == "javac" ]
then
if [ ${mainclass} ]
then
nohup java -cp conf:lib\*.jar:${packageName}.jar ${mainclass} >${baseDirPath}/${packageName}.out 2>&1 &
#nohup java -cp conf:lib\*.jar:${packageName}.jar ${mainclass} >/dev/null 2>&1 &
fi
elif [ "${languageType}" == "java" ]
then
nohup java -jar ${baseDirPath}/${baseZipName}/${packageName}.jar >/dev/null 2>&1 &
# java -jar ${baseDirPath}/${baseZipName}/${packageName}.jar
elif [ "${languageType}" == "netcore" ]
then
#nohup dotnet run ${baseDirPath}/${baseZipName}/${packageName} >/dev/null 2>&1 &
nohup ${baseDirPath}/${baseZipName}/${packageName} >/dev/null 2>&1 &
fi
#查询是否有启动进程
getPid
if [ ${pid} ]
then
echo "已启动"
#nohup日志
tail -n 50 -f ${baseDirPath}/${packageName}.out
else
echo "启动失败"
fi
fi
}
#停止程序
function stop()
{
getPid
if [ ${pid} ]
then
echo "停止程序---------------------------------------------"
kill -9 ${pid}
getPid
if [ ${pid} ]
then
#stop
echo "停止失败"
else
echo "停止成功"
fi
fi
}
#启动时带参数,根据参数执行
if [ ${#} -ge 1 ]
then
case ${1} in
"start")
start
;;
"restart")
start
;;
"stop")
stop
;;
"unzip")
#执行解压
shenniu_unzip
#执行启动
start
;;
*)
echo "${1}无任何操作"
;;
esac
else
echo "
command如下命令:
unzip:解压并启动
start:启动
stop:停止进程
restart:重启
示例命令如:./shenniu_publish start
"
fi
输入参数判断
#! /bin/bash
set -e
export CUR="shell"
# shellcheck disable=SC2164
cd $CUR
# 判断输入参数数量 > 1 ?
if [ ${#} -ge 1 ]; then
case "$1" in
"dev" ) bash dev-push.sh ;;
"master") bash master-push.sh ;;
"both" ) bash dev-push.sh && bash master-push.sh ;;
"tag" ) case $2 in
"-d") bash tag-delete.sh ;;
"" ) bash tag-release.sh ;;
* ) echo 'undefined second argument!' ;;
esac ;;
*) echo "not input argument" ;;
esac
else
echo "
[Bash基础命令]:
1) dev : 推送dev
2) master : 推送master
3) both : 同时推送dev与master
4) tag : 推送tag
5) tag -d : 删除tag
命令示例: bash push.sh dev
"
fi
FAQ
- name: command not found
# 变量赋值"="前后不能有空格
name="coulsonzero"
- [] & if[ ]: command not found
# if [ ]: 中间需要空格
if [ ${pid} ]
then
echo "great"
else
echo "pope"
fi
- linux 空格和 window 空格不一致
$ vim start.sh
# 添加此命令保存
set ff=unix