shell脚本总结

前言

总结了工作中遇到的一些shell使用情况,不定期更新,留作后续参考。

总结

  1. shell函数以及传参
#/bin/bash
# 函数形式
add(){
    # 参数 1
    para1=$1
    # 参数 2
    para2=$2
    # 参数处理
    sum=`echo "$para1 $para2"|awk '{printf("%d",$1+$2)}'`
    echo $sum
    # 返回,注意,只能是整数0~255
    return 0
}
# 调用函数 add
add 1 2
# 打印执行结果(即为return 的返回值)
echo $?
# 想要得到函数处理结果,尤其是需要获取字符串时,可以使用此方式
a=$(add 1 2)
echo $a

return:“假的”返回; echo:“真的”返回

  1. 数组
array=(1 2 3 "a" b c)
for i in ${array[*]}
do
    echo $i
done
  1. case
input=1
case $input in
    1)
    echo "one"
    ;;
    2)
    echo "two"
    ;;
    3|4|5|6)
    echo "$input"
    ;;
    *)
    echo "not find"
    ;;
esac
  1. if
# [[]]中间的条件需要和左右括号各间隔一个空格
if [[ 条件1 ]]; then
elif [[ 条件2 ]]; then
else
fi
  1. 调用linux指令,并捕获返回值
a=`ls`
a=`cat 1.txt`
a=$(ls)
  1. 字符串处理
a="1/2/3.txt"
# 删除掉最后一个 / 及 / 左边的字符串,得到 3.txt
b=${a##*/}
# 删除最后一个 / 及 / 右边的字符串,得到 1/2
c=${a%/*}
# 删除最后一个 . 及 . 右边的字符串,得到 3
d=${b%.*}
# 从第4位开始截取a, 得到/3.txt
echo ${a:3}
# 获取字符串a的长度
echo ${#a}
# 大写转小写
tst="THIS IS A TEST"
tst2=`echo "$tst" | awk '{print tolower($0)}'`
# 小写转大写
tst3=`echo "$tst2"| awk '{print toupper($0)}'`

参考博客https://www.cnblogs.com/yutingliuyl/p/7236501.html

  1. 询问
a=1
if [[ a==1 ]]; then
    echo -e "\n"
    # 打印红色提示
    printf  "\033[0;31mWarning: a=$a\033[0m";
    echo -e "\n"
    # 询问是否继续
    read -r -p "Are you sure to be continue? [Y/n] " input
    case $input in
        [yY][eE][sS]|[yY])
        echo "ok, let's continue"
        echo "-----------------------------------------"
        ;;
        [nN][oO]|[nN])
        exit 0
        ;;
        *)
        echo "Invalid input..."
        exit 1
        ;;
    esac
fi
  1. 运算符
-e file/dir 判断文件或文件夹是否存在,如果是,返回true
$a -eq $b 判断a是否等于b,等于则返回true
$a -ne $b 判断a是否不等于b,等于则返回false
$a -gt $b 判断a是否大于b,如果是,返回true
$a -lt $b 判断a是否小于b,如果是,返回false
$a -ge $b 判断a是否大于等于b,如果是,返回true
$a -le $b 判断a是否小于等于b,如果是,返回true
  1. 多行注释
:<<EOF
这是注释
EOF

多行注释还有其它形式,具体可以参考菜鸟教程

  1. 传递参数
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。如"$*"用__"__括起来,以"$1 $2 ... $n"的形式输出所有参数
$$ 脚本运行的当前ID号
$! 后台运行的最后一个进程的ID号
#@ 与__$*__相同,但是使用时加引号,并在引号中返回每个参数。如"#@"用__""__括起来,以"$1" "$2" ... "$n" 的形式输出所有参数
$- 显示Shell使用的当前选项,与__set__命令功能相同
$? 显示最后命令的退出状态。0表示没有错误,其它任何值表示有错误。

8,9,10参考菜鸟教程https://www.runoob.com/linux/linux-shell.html

  1. 根据端口号查看进程命令
    get_pidname_by_port.sh [PORT]
#!/bin/bash
function Usage(){
    echo "Usage:"
    echo "$0 [PORT]"
    exit 0
}

function getCmdByPid(){
	pid=$1
	cmd=`ps -p $pid -o command=`
	dir=`ls -la /proc/${pid}/ |grep cwd|awk -F' ' '{print $11}'`
        echo $cmd "dir:"$dir
}


PORT=$1
if [[ $PORT == "" ]];then
    Usage
fi

pids=`lsof -i:$PORT|grep -v PID|awk -F' ' '{print $2}'|xargs`

if [[ $pids != '' ]];then
	echo "PORT PID COMMAND DIR"
fi

for s in $pids
do
	cmdStr=$(getCmdByPid $s)
	echo $PORT $s $cmdStr
done

  1. grep
  • grep -v 不显示的内容,比如ps -ef|grep -v grep就会在进程中过滤调grep命令本身
  • grep -E "内容1|内容2" 扩展正则表达式,返回包含内容1或内容2的行
  1. 自定义日志管理
  • 格式化输出 时间:信息
  • 日志文件大小管理:超过100M自动清空
    log.sh
#!/bin/bash

# 日志输出
logPath=my.log
logMaxSize=$(echo "100 1024 1024"|awk '{printf("%d",$1*$2*$3)}')
function log()
{
    msg=$1
    # 日志大小超过最大,清空日志
    if [[ -e $logPath  ]];then
        logSize=$(ls -l $logPath|awk '{print $5}')
        if [[ $logSize -gt $logMaxSize  ]];then
            echo -n "" > $logPath
        fi
    fi
    date=$(date "+%Y-%m-%d %H:%M:%S")
    logStr=$date": "$msg
    echo $logStr
    echo $logStr >> $logPath
}

log "hello"
chmod +x log.sh && ./log.sh
# 2023-03-25 16:55:49: hello
  1. 启停 python http.server 文件服务

start.sh

#!/bin/bash
port=12123
log=out.log

pids=`ps -ef|grep "python3 -m http.server -b 0.0.0.0 ${port}"|grep -v grep|awk -F ' ' '{ print $2}'|xargs`
if [[ ${pids} != "" ]];then
    kill -9 ${pids}
    echo "${pids} have been killed"
fi

nohup python3 -m http.server -b 0.0.0.0 ${port} 2>&1 >> ${log} &

echo "http file server started: http://0.0.0.0:${port}"

kill.sh

#!/bin/bash
port=12123
log=out.log

pids=`ps -ef|grep "python3 -m http.server -b 0.0.0.0 ${port}"|grep -v grep|awk -F ' ' '{ print $2}'|xargs`
if [[ ${pids} != "" ]];then
    kill -9 ${pids}
    echo "${pids} have been killed"
fi
  1. 设置文件/文件夹被占用
    有时为了方便测试或其他要求,需要将文件/文件夹设置为被占用,脚本使用chattr实现
#!/bin/bash
# 设置一个文件/文件夹是否被占用

path=$1
action=$2

function Usage()
{
    echo -e "Usage:${0} [file_path] [f/uf]"
    echo -e "file_abs_path: file  path"
    echo -e "f/uf: f-fixed, uf-unfixed"
    exit 0
}

if [[ ${path} == "" || ${action} == "" ]];then
    Usage
fi


if [[ -e ${path} ]];then
    echo -e "check file exists success"
else
    echo -e "Error: ${path} not exists"
    Usage
fi


echo -e "start get file org status:"
lsattr -d ${path}
file_status=`lsattr -d ${path}|grep "i"|wc -l`
if [[ ${file_status} > 0 ]];then
    echo -e "${path} is fixed"
else
    echo -e "${path} is unfixed"
fi

echo -e ""
echo -e "******"

if [[ ${action} == "f" ]];then
    echo -e "start set ${path} fixed"
    chattr +i ${path}
    lsattr -d ${path}
    echo -e "******"
    echo -e "set ${path} fixed finished"
elif [[ ${action} == "uf" ]];then
    echo -e "start set ${path} unfixed"
    chattr -i ${path}
    lsattr -d ${path}
    echo -e "******"
    echo -e "set ${path} unfixed finished"
else
    echo -e "Error: ${action} not in (f, uf)"
    Usage
fi
  1. 关机前可以手动执行的脚本
    关机前手动执行脚本,可以手动配置成service,目前做到的是kill所有想停止的任务,停止所有的podman容器

handle_bf_shutdown.sh

#!/bin/bash

function kill_process()
{
        key_name=$1
        if [[ ${key_name} == "" ]];then
                echo -e "-- kill_process: key_name is None"
                return
        fi
        
        echo -e "-- start kill ${key_name}"

        pids=`ps -ef|grep ${key_name}|grep -v grep|awk -F ' ' '{print $2}'|xargs`
        if [[ ${pids} != "" ]];then
                echo -e "-- find pid:${pids}, start kill"
                kill -9 ${pids}
        fi

}



function kill_all_needed_process()
{
        echo -e "### start kill all process needed"
        # 此处可以扩展任何想kill掉的任务关键词,注意用空格隔开不要用逗号,如
        # keys=("task1" "task2")
        keys=("handle_old_data")
        
        for item in "${keys[@]}"
        do
                kill_process ${item}
        done

}


function stop_all_container()
{
        echo -e "### start stop all container"
        podman ps -a --format={{.Names}} | while read container_name
        do
                echo -e "start stop ${container_name}"
                podman stop ${container_name}
        done

}


kill_all_needed_process

stop_all_container
posted @ 2021-10-29 17:31  BrianSun  阅读(59)  评论(0编辑  收藏  举报