Linux Shell脚本

一、Shell语法

  1. 运行方式

    A. 作为可执行文件:脚本保存到文件中(如:web-admin.sh),并切换到当前文件目录,赋予脚本执行权限chmod +x ./web-admin.sh,执行脚本./web-admin.sh;

      附:linux下.表示当前目录,..表示父目录,./表示当前目录的全路径,如果运行某个可执行文件可用cd /usr/local/nginx/sbin && ./nginx或者绝对路径/usr/local/nginx/sbin/nginx;

    B. 作为解释器参数:/bin/sh web-admin.sh,这种在脚本里第一行指定解释器信息会忽略。

  2. 变量

    A. 变量定义不能使用$符号,使用变量是在变量名前加$符号,最好带上花括号,有助于解释器识别变量的边界;

    B. 变量名和等号之间不能有空格;

    C. 完整的表达式要被反引号 ` ` 包含;

    D. 双引号里可以有变量,还可以出现转义字符,但是单引号里变量是无效的,因为任何字符都会原样输出;

    E. 引号中嵌套引号,可以使用\来转义。

  3. 参数传递

    A. 执行Shell脚本时,可向脚本传递参数,脚本内获取参数的格式为:$n,n代表数字,从1开始,1表示第一个参数,注意$0表示执行的文件绝对路径名。

  4. 命令

    A. echo:用于向窗口输出字符串文本;

    B. printf:格式化输出文本;

    C. test:检查条件是否成立。

    D. eval:l执行变量中的命令,注意ssh 远程执行时使用双引号替代单引号,将命令发送之前替换对本地值;

  5. 输入/输出重定向

    A. n >> file:将文件描述符为n的文件以追加的方式重定向到file;

    B. n >& m:将输出文件m和n合并。 

  6. if else流程控制

    A. if中括号前后一定要加空格,当判断中的变量有可能为空时需要加双括号[[]]

    B. -eq,-ne等比较符只能用于数字比较,字符串比较用==,!=等处理;

      -gt(大于)、-eq(等于)、-lt(小于)、-ge(大于等于)、-le(小于等于)、-ne(不等于)

    C. -d:判断目录是否存在;

      -f:判断常规文件是否存在;

      -z:判读字符串是否是空串。

# 如果文件夹不存在,创建文件夹
if [ ! -d "/myfolder" ]; then
  mkdir /myfolder
fi

   7. for循环语句

for var in item1 item2 ... itemN 
do
command1
command2
...
commandN
done

  8. 数组Array

    A. 获取数组元素个数:${#array[@]} 或 ${#array[*]};

    B. 获取数组所有元素:${array[@]} 或 ${array[*]};

    C. 获取数组下标:${!array[@]} ;

    D. 从数组n位置开始取m个元素:${array[@]:n:m} ;

    E. 数组合并:new_array=(${array1[@]} ${array2[@]})

    F. 对数组进行去重排序:array=($(echo ${array[@]} | sed 's/ /\n/g' | sort )) | uniq;

    G. 数组转字符串:str=$(IFS=,; echo "${array[*]}");

    H. 多行内容变数组:| xargs,将换行和空白变成空格的单行;

  9. 键值对Map

    A. shell数组只支持一维数组,并且没有map这种结构,实际是用关联数组来模拟的;

    B. 声明格式:declare -A map,支持索引下标为字符串;

  10. 函数

    A. 函数定义格式:可以直接funname()定义不带参数

[ function ] funname [()]

{

    action;

    [return int;]

}

    B. 函数调用:直接funname即可,所有函数需要先声明再调用,即将函数定义放在脚本开始位置

  11. 特殊符号

    A. $n 脚本的第n个参数值,n=1..9;

    B. $? 执行上一个指令的返回值 (显示最后命令的退出状态,0表示没有错误,其他任何值表明有错误);

    C. IFS 分隔符:如IFS='=',表示以等号分割;

   12. 其他常见写法

    A. shell远程执行命令:前提是配置ssh免密登陆,如:ssh root@ip "sh linux.sh; ip a",双引号必须有,否则第二个命令在本地执行,命令之间用分号来隔开;

    B. 判读字符串是否以END字符开头:if [[  $str == END* ]],注意:通配符不能使用引号括起来,比较语句使用双中括号括起来;

    C. 读取配置文件前15行内容:head -15 ./resource.txt | while read ip service,注意在管道符中操作全局变量会不生效,因为管道符是非内建指令,会创建子shell来运行命令,运行完就会销毁变量,故不推荐使用;

 

二、LInux输出重定向到文件和标准输出

  1. Bash或Linux shell标准I/O流,程序输出进入标准输出流,错误消息进入标准错误流,默认情况下,输入流和错误流都打印在屏幕上;

    A. 0-STDIN,标准输入流;

    B. 1-STDOUT,标准输出流;

    C. 2-STDERR,标准错误流;

  2. 重定向标准输出流

    A. 将命令输出(stdout)重定向到文件:command > file 或 command 1 > file;

    B. 重定向标准错误流(stderr):command 2 > file;

    C. 禁止在屏幕上显示错误信息:command 2 > /dev/null;

    D. 将stderr重定向stdout并将错误信息发送到标准输出相同的文件:command > file 2&1;

    E. 标识符限定输入:EOF表示自定义终止符。

    注意:使用>时会将文件内容会覆盖,使用>>时文件内容追加。

 

三、常见错误

  1. 错误一:shell脚本执行结果报$'\r': 未找到命令;

    原因:脚本是使用VS Code编辑器编写的,查找是换行符的问题,注意是LF,而不是CRLF。

   2. 错误二:/bin/bash^M: bad interpreter: No such file or directory

    原因:脚本是使用Notepad++编辑器编写的,查找还是换行符的问题,注意是Unix,不是Windows。

 

四、使用举例

  1. 检测网络是否ping通

# 在内网下,DNS不能配置公网,否则Docker服务因为DNS解析巨慢
ping -c1 www.baidu.com
if [ $? -ne 0 ];then
    echo "当前环境判断为隔离内网环境"
    sed -ri '/(114.114.114.114|8.8.)/d' /etc/resolv.conf
    echo -e "#nameserver 114.114.114.114\n#nameserver 8.8.8.8" >> /etc/resolv.conf
else
    echo "当前环境判断为可访问公网环境"
fi

  2. Jenkins SpringBoot jar包启动脚本:sh web-admin.sh

#!/bin/bash
PROJECT_PACKAGE=web-admin-0.0.1-SNAPSHOT.jar
PATH_NAME=test/web-admin/web-admin
# 删除文件
rm -rf /project/web/jar/$PROJECT_PACKAGE
# 拷贝文件
cp /var/lib/jenkins/workspace/$PATH_NAME/target/$PROJECT_PACKAGE /project/web/jar/
# 切换路径
cd /project/web/jar/

pid=`ps -ef | grep $PROJECT_PACKAGE | grep -v grep | awk '{print $2}'`
if [ -n "$pid" ]
then
   # 杀死存在进程
   kill -9 $pid
fi

# 避免项目启动之后被Jenkins杀掉
BUILD_ID=dontKillMe
# 执行
nohup java -jar $PROJECT_PACKAGE --spring.profiles.active=test >> /project/web/log/web-admin.log 2>&1 &
# echo 命令用于向窗口输出文本
echo "web-admin项目启动成功!"

   3. MySQL全量备份脚本:定时任务生效就行

#!/bin/bash
# mysqldump的路径
DUMP=/usr/bin/mysqldump
# 数据库登录名
DB_USER=root
# 数据库登录密码
DB_PASSWORD=password
# 备份文件目录
BAK_DIR=/admin
# 当前时间
DATE=`date +%Y%m%d%H%M`

# 目录不存在就创建
if [ ! -d "$BAK_DIR" ]; then
    mkdir -p $BAK_DIR
fi

$DUMP -u$DB_USER -p$DB_PASSWORD --lock-all-tables --databases admin | gzip >$BAK_DIR/${DATE}.sql.gz

# 只保留一周的备份数据
find $BAK_DIR -type d -mtime +7 -name "*.sql.gz" -exec rm -rf {} \;

echo "数据库全量备份成功!"

 

posted @ 2021-01-02 10:53  如幻行云  阅读(94)  评论(0编辑  收藏  举报