Shell脚本基础

基本结构

1
#!/bin/sh

变量

脚本所有变量都为字符串

声明变量

1
2
nodeList=
cmdBuild="build"

使用变量

1
2
cmd=$cmdBuild
cmdFile=${cmdBuild}_file.log

截断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ list="app _install util _install scripts logs"
$ echo $list
app _install util _install scripts logs

# 将标识符_install及尾部去除,只保留头部
$ echo ${list%_install*}
app _install util
$ echo ${list%%_install*scri*}
app

# 将标识符_install及头部去除,只保留尾部
$ echo ${list#*_install}
util _install scripts logs
$ echo ${list##*_install}
scripts logs

数组

声明数组

1
2
3
4
5
6
7
8
9
10
11
defaultNodeList=`ls -d */ | awk '{gsub(/\//,""); print $0}'`

# 直接输出
$ echo $defaultNodeList
app _install util

# 循环输出
$ for node in $defaultNodeList; do echo $node; done
node: app
node: _install
node: util

增加元素

1
2
3
4
# 数组尾部增加元素
defaultNodeList="$defaultNodeList tailItem"
# 数组头部增加元素
defaultNodeList="headItem $defaultNodeList"

删除元素

方法1,字符串截断,列表不能有重复元素

1
2
delim="_install"
defaultNodeList="${defaultNodeList%%${delim}*} ${defaultNodeList##*${delim}}"

方法2,关键字替换,可以替换所有元素

方法3,重新创建新数组,将指定元素丢弃

判断

单个条件

1
2
3
4
5
6
7
if [ -z "$1" ]; then
echo "Update cmd is empty, skip it."
elif [ -z "$2" ]; then
echo "Directory($s) is runtime, skip it."
else
echo "All is ok."
fi

多个条件

1
2
3
if [ ! -z "$nodeList" ] && [ "$cmd" = "$cmdBuild" ]; then
echo "Update cmd is empty, skip it."
fi

switch型

1
2
3
4
5
6
7
8
case "$1" in
-n) updateNodeList $2; shift; shift; ;;
--start) shift; updateCmd $cmdStart; ;;
--stop) shift; updateCmd $cmdStop; ;;
-b|--build) shift; updateCmd $cmdBuild; ;;
-h|--help) usage; ;;
*) error "Unknown option($1)"; usage; ;;
esac

循环

while型

1
2
3
4
while [ -n "$1" ]; do
echo "$1"
shift
done

for each型

1
2
3
for node in $nodeList; do
echo "node: $node"
done

函数

声明函数

1
2
3
4
info()
{
echo "\033[32m[INFO]" $*"\033[0m"
}

输入参数:$1~$9 分别代表参数1~9. $0为执行脚本文件路径

返回参数:return [RET],值为0-255;不写值为默认0;

调用函数

直接调用

1
$ info "Exec cmd $cmd." "All is ok"

获取返回值判断,类似三元表达式

1
2
3
4
5
6
# 单步处理可以直接写
testPid $pid && echo "$pid is ok" || echo "$pid is failed"

# 多步处理需要增加括号
testPid $pid && info "$node($pid) start done." ||
(error "$node($pid) start failed." && echo `tail -n 5 $pwdPath/$node/${node}_out.log` && exit 255)

常用命令

返回文件的绝对路径

1
2
$ readlink -f go.mod 
/root/project/softarch/go.mod

dirname

返回文件或文件夹的上级路径

1
2
$ dirname ~/project/softarch
/root/project

echo

显示字符串

1
2
echo "hello world"
echo "hello world\n你好,世界\n"

控制显示颜色

1
2
3
4
5
6
# 绿色字体
echo "\033[32m[INFO] hello world\033[0m"
# 黄色字体
echo "\033[33m[WARN] hello world\033[0m"
# 红色字体
echo "\033[31m[ERROR] hello world\033[0m"

nohup

脱离终端启动程序

启动程序时,获取程序运行pid

1
nohup ./$node >$pwdPath/$node/${node}_out.log 2>&1 & echo $!>/tmp/.${node}.pid

组合命令

显示当前路径下所有文件夹名称

1
2
3
4
$ ls -d */ | awk '{gsub(/\//,""); print $0}'
app
_install
util