【Linux】分享几个实用的shell脚本


工作中,为了解决一些问题或者自动处理一些繁琐的操作,我常常会写一些脚本。

每次写脚本也花了不少时间,这里记录一下几个工作中用到的脚本,之后再用到的时候找起来容易些~

推荐文章:Hello系列 | Shell编程必备简明基础知识

1、一键配置脚本

#! /bin/bash
#####################################################################
# 脚本功能:一键配置脚本
#####################################################################

echo "################################# 解压、拷贝文件 #################################"

# 解压安装文件
tar xf robot_install_files.tar
echo "tar xf robot_install_files.tar"

SRC_INSTALL_FILE_PATH=./robot_install_files
ROBOT_USR_PATH=/data

# mqtt
mv ${SRC_INSTALL_FILE_PATH}/mqtt ${ROBOT_USR_PATH}
echo "mv ${SRC_INSTALL_FILE_PATH}/mqtt ${ROBOT_USR_PATH}"

# rsync
mv ${SRC_INSTALL_FILE_PATH}/rsync /usr/bin
echo "mv ${SRC_INSTALL_FILE_PATH}/rsync /usr/bin"

# bin
SRC_BIN_DIR=${SRC_INSTALL_FILE_PATH}/bin
DEST_BIN_DIR=/data/bin
if [ -d ${DEST_BIN_DIR} ]; then
    echo "${DEST_BIN_DIR} exit, cp config"
    cp ${SRC_BIN_DIR}/* ${DEST_BIN_DIR}
else
    echo "${DEST_BIN_DIR} not exit, mv config"
    mv ${SRC_BIN_DIR} ${ROBOT_USR_PATH}
fi

# cfg
SRC_CFG_DIR=${SRC_INSTALL_FILE_PATH}/cfg
DEST_CFG_DIR=/data/cfg
if [ -d ${DEST_CFG_DIR} ]; then
    echo "${DEST_CFG_DIR} exit, cp config"
    cp ${SRC_CFG_DIR}/* ${DEST_CFG_DIR}
else
    echo "${DEST_CFG_DIR} not exit, mv config"
    mv ${SRC_CFG_DIR} ${ROBOT_USR_PATH}
fi

# lib
SRC_LIB_DIR=${SRC_INSTALL_FILE_PATH}/lib
DEST_LIB_DIR=/data/lib
if [ -d ${DEST_LIB_DIR} ]; then
    echo "${DEST_LIB_DIR} exit, cp config"
    cp ${SRC_LIB_DIR}/* ${DEST_LIB_DIR}
else
    echo "${DEST_LIB_DIR} not exit, mv config"
    mv ${SRC_LIB_DIR} ${ROBOT_USR_PATH}
fi

chmod 777 ${ROBOT_USR_PATH}/bin/*

echo "################################# thttpd配置 #################################"
CURRENT_DIR=$PWD
WEB_PAGE_SRC_DIR=${SRC_INSTALL_FILE_PATH}/webpage
cp ${CURRENT_DIR}/mqtt/lib/libmos* /lib/
mkdir -p /etc/thttpd
chmod 755 /etc/thttpd
touch /etc/thttpd/thttpd.log
chmod 666 /etc/thttpd/thttpd.log
touch /etc/thttpd/thttpd.pid
chmod 666 /etc/thttpd/thttpd.pid
mkdir -p /etc/thttpd/html
chmod 755 /etc/thttpd/html
mkdir -p /etc/thttpd/html/cgi-bin
chmod 755 /etc/thttpd/html/cgi-bin
cp ${WEB_PAGE_SRC_DIR}/thttpd.conf /etc
chmod 777 /etc/thttpd.conf
cp ${WEB_PAGE_SRC_DIR}/index.html /etc/thttpd/html
chmod 644 /etc/thttpd/html/index.html
cp -r ${WEB_PAGE_SRC_DIR}/jquery /etc/thttpd/html
chmod 777 /etc/thttpd/html/jquery
chmod 666 /etc/thttpd/html/jquery/*
cp ${WEB_PAGE_SRC_DIR}/thttpd /bin
chmod 777 /bin/thttpd
cp ${WEB_PAGE_SRC_DIR}/MowerHTML.cgi /etc/thttpd/html/cgi-bin
chmod 755 /etc/thttpd/html/cgi-bin/MowerHTML.cgi

echo "################################# 配置环境变量 #################################"
echo "${CURRENT_DIR}"
if [ -d ${ROBOT_USR_PATH}/mqtt ]; then
    echo "export LD_LIBRARY_PATH=$CURRENT_DIR/mqtt/lib/:/data/lib:$LD_LIBRARY_PATH" >> /etc/profile
    echo "export PATH=$CURRENT_DIR/mqtt/bin/:$CURRENT_DIR/mqtt/sbin:$PATH" >> /etc/profile
    echo "user root" >> $CURRENT_DIR/mqtt/etc/mosquitto/mosquitto.conf
    echo "mosquitto -d -c $CURRENT_DIR/mqtt/etc/mosquitto/mosquitto.conf" >> /etc/profile
    echo "cd /data/bin/" >> /etc/profile
    echo "pwd" >> /etc/profile
    source /etc/profile
else
    echo "mqtt not exit"
fi

echo "############################### 删除解压文件 ###############################"
rm -rf /data/robot_install_files
echo "rm -rf robot_install_files"

每次装新机器都需要安装一些文件、进行一些必要配置,把这些繁琐的工作交给脚本。

2、log并自动合并

#!/bin/bash

#####################################################################
# 脚本功能:一键获取log并自动合并
#####################################################################

# 机器IP
ROBOT_IP=172.13.10.36

# PC端存log的路径
PC_SAVE_LOG_PATH=.
APP_LOG_TMP_PATH=${PC_SAVE_LOG_PATH}/app_tmp_dir

# 合成的文件
APP_MERGE_LOG_FILE=${PC_SAVE_LOG_PATH}/app_log_$(date +%m%d_%H%M)

# 机器log路径(不可修改!)
ROBOT_APP_LOG_PATH=/data/bin/app_log

echo "################################# 合成APP LOG文件 #################################"
# 创建app log临时文件夹
if [ -d ${APP_LOG_TMP_PATH} ]; then
    echo "rm -rf ${APP_LOG_TMP_PATH}"
    rm -rf ${APP_LOG_TMP_PATH}
fi
echo "create app_tmp_dir"
mkdir -p ${APP_LOG_TMP_PATH}

# 拉取app log文件
echo "pull robot ${ROBOT_APP_LOG_PATH}"
sshpass -p 1 rsync -avz --progress root@${ROBOT_IP}:${ROBOT_APP_LOG_PATH}/*.log ${APP_LOG_TMP_PATH}

# 获取LOG文件最后一次修改的时间戳
APP_LOG_FILE_LIST=($(ls ${APP_LOG_TMP_PATH}/*.log))
for i in "${!APP_LOG_FILE_LIST[@]}";
do
    APP_LOG_FILE="${APP_LOG_TMP_PATH}/${i}.log"
    # echo ${APP_LOG_FILE}
    # echo "i = "${i}
    APP_LOG_FILE_TIME_ARR[${i}]=$(stat -c %Y ${APP_LOG_FILE})
    APP_LOG_FILE_DATE_ARR[${i}]=$(date '+%Y-%m-%d %H:%M:%S' -d @${APP_LOG_FILE_TIME_ARR[${i}]})
    echo ${APP_LOG_FILE} ${APP_LOG_FILE_DATE_ARR[${i}]} ${APP_LOG_FILE_TIME_ARR[${i}]}
    APP_LOG_FILE_TIME_SORT_ARR[${i}]=${APP_LOG_FILE_TIME_ARR[${i}]}
    # echo ${APP_LOG_FILE_TIME_SORT_ARR[${i}]}
done

# 时间戳从小到大排序
for((i = 0; i < ${#APP_LOG_FILE_TIME_SORT_ARR[@]}; i++))
{
   for((j = 0; j < ${#APP_LOG_FILE_TIME_SORT_ARR[@]} - 1; j++))
   {
     if [[ ${APP_LOG_FILE_TIME_SORT_ARR[j]} -gt ${APP_LOG_FILE_TIME_SORT_ARR[j+1]} ]]; then
          tmp=${APP_LOG_FILE_TIME_SORT_ARR[j]}
          APP_LOG_FILE_TIME_SORT_ARR[j]=${APP_LOG_FILE_TIME_SORT_ARR[j+1]}
          APP_LOG_FILE_TIME_SORT_ARR[j+1]=$tmp
      fi
    }
}
echo "app log timestamp after sort"
echo ${APP_LOG_FILE_TIME_SORT_ARR[@]}

# 记录时间戳从小到大的文件
for((sort_index = 0; sort_index < ${#APP_LOG_FILE_TIME_SORT_ARR[@]}; sort_index++))
{
    for((ori_index = 0; ori_index < ${#APP_LOG_FILE_TIME_ARR[@]}; ori_index++))
    {
        # echo ${ori_index}
        if [ ${APP_LOG_FILE_TIME_SORT_ARR[${sort_index}]} = ${APP_LOG_FILE_TIME_ARR[${ori_index}]} ]; then
            APP_LOG_INDEX_ARR[${sort_index}]=${ori_index}
        fi
    }
}
echo "APP_LOG_INDEX_ARR=${APP_LOG_INDEX_ARR[@]} len=${#APP_LOG_INDEX_ARR[@]}"

# 总app log文件合成
if [ ${#APP_LOG_INDEX_ARR[@]} -le 0 ]; then
    echo "app log merge error!!"
else
    touch ${APP_MERGE_LOG_FILE}
    for i in ${!APP_LOG_INDEX_ARR[@]};
    do
        $(cat ${APP_LOG_TMP_PATH}/${APP_LOG_INDEX_ARR[${i}]}.log >> ${APP_MERGE_LOG_FILE} 2>&1)
    done
    echo "merge app_log success!! file_name: ${APP_MERGE_LOG_FILE}"
fi

# 删除app log临时文件
echo "clean tmp app log file"
rm -rf ${APP_LOG_TMP_PATH}

机器上的app的log循环存储若干份,要看完整log需要自己从机器上拷贝各log文件,并进行合并。

其中,有用到一个rsync远程同步工具,可参考往期文章:本地与远程设备之间如何有效地进行文件同步?

3、一键更新程序

#! /bin/bash
#####################################################################
# 脚本功能:一键更新程序
#####################################################################

# 1、使用wifi更新,输入命令:./push_all_pros.sh wifi
# 2、使用adb更新,输入命令:./push_all_pros.sh adb

# 机器IP
ROBOT_IP=172.13.10.36

# 源路径(PC路径)
AI_SO_LIB_SRC_PATH=./AI/data/lib
AI_CONFIG_SRC_PATH=./AI/data/config
AI_MODEL_SRC_PATH=./AI/data/model
AI_EXE_FILE_SRC_PATH=./AI/data/bin
APP_EXE_FILE_SRC_PATH=./app

# 目标路径(机器路径)
AI_SO_LIB_TARTET_PATH=/data/lib
AI_CONFIG_TARGET_PATH=/data/config
AI_MODEL_TARGET_PATH=/data/model
AI_EXE_FILE_TARGET_PATH=/data/bin
APP_EXE_FILE_TARGET_PATH=/data/bin

# 程序名称
AI_EXE_NAME=ai
APP_EXE_NAME=app

# adb传输
if [ $1 = "adb" ]; then
	# 更新AI lib files
	echo "========== AI_SO_FILE =========="
	SO_LIST=($(ls ${AI_SO_LIB_SRC_PATH}/*.so))
	for i in "${!SO_LIST[@]}";
	do
	    SO_NAME=${SO_LIST[$i]}
	    echo "push ${SO_NAME} ${AI_SO_LIB_TARTET_PATH} ..."
	    adb push ${SO_NAME} ${AI_SO_LIB_TARTET_PATH}
	done
	echo -e "\n"
	# 更新AI cfg files
	echo "========== AI_INI_FILE =========="
	INI_LIST=($(ls ${AI_CONFIG_SRC_PATH}/*.ini))
	for i in "${!INI_LIST[@]}"
	do
		INI_NAME=${INI_LIST[$i]}
		echo "push ${INI_NAME} ${AI_CONFIG_TARGET_PATH} ..."
		adb push ${INI_NAME} ${AI_CONFIG_TARGET_PATH}
	done
	echo -e "\n"
	# 更新AI model files
	echo "========== AI_MODLE_FILE =========="
	MODEL_LIST=($(ls ${AI_MODEL_SRC_PATH}/*.rknn))
	for i in "${!MODEL_LIST[@]}"
	do
		MODEL_NAME=${MODEL_LIST[$i]}
		echo "push ${MODEL_NAME} ${AI_MODEL_SRC_PATH} ..."
		adb push ${MODEL_NAME} ${AI_MODEL_TARGET_PATH}
	done
	echo -e "\n"
	# 更新AI pro
	echo "========== AI_EXE_FILE =========="
	echo "push ${AI_EXE_FILE_SRC_PATH}/${AI_EXE_NAME} ${AI_EXE_FILE_TARGET_PATH} ..."
	adb push ${AI_EXE_FILE_SRC_PATH}/${AI_EXE_NAME} ${AI_EXE_FILE_TARGET_PATH}
	echo -e "\n"
	# 更新app pro
	echo "========== APP_EXE_FILE =========="
	echo "push ${APP_EXE_FILE_SRC_PATH}/${APP_EXE_NAME} ${APP_EXE_FILE_TARGET_PATH} ..."
	adb push ${APP_EXE_FILE_SRC_PATH}/${APP_EXE_NAME} ${APP_EXE_FILE_TARGET_PATH}
# wifi传输
elif [ $1 = "wifi" ]; then
	echo "========== AI_EXE_FILE =========="
	echo "push ${AI_EXE_FILE_SRC_PATH}/${AI_EXE_NAME} ${AI_EXE_FILE_TARGET_PATH} ..."
	sshpass -p 1 scp ${AI_SO_LIB_SRC_PATH}/*.so root@${ROBOT_IP}:${AI_SO_LIB_TARTET_PATH}
	sshpass -p 1 scp ${AI_CONFIG_SRC_PATH}/*.ini root@${ROBOT_IP}:${AI_CONFIG_TARGET_PATH}
	sshpass -p 1 scp ${AI_MODEL_SRC_PATH}/*.rknn root@${ROBOT_IP}:${AI_MODEL_TARGET_PATH}
	sshpass -p 1 scp ${AI_EXE_FILE_SRC_PATH}/${AI_EXE_NAME} root@${ROBOT_IP}:${AI_EXE_FILE_TARGET_PATH}
	echo "========== APP_EXE_FILE =========="
	echo "push ${APP_EXE_FILE_SRC_PATH}/${APP_EXE_NAME} ${APP_EXE_FILE_TARGET_PATH} ..."
	sshpass -p 1 scp ${APP_EXE_FILE_SRC_PATH}/${APP_EXE_NAME} root@${ROBOT_IP}:${APP_EXE_FILE_TARGET_PATH}
	echo -e "push all pro end!"
fi

每次发布版本,都需要更新好多文件,一个一个传有些繁琐,故写了一个一键更新脚本。可使用无线更新,也可以使用有线更新。

4、一键运行程序

#!/bin/bash

#####################################################################
# 脚本功能:一键运行所有程序
#####################################################################

# 脚本log名称
APP_SCRIPT_RUN_LOG=app_script_log

# 每次启动都先把脚本的log给删掉
if [ -f ${APP_SCRIPT_RUN_LOG} ]; then
	rm -f ${APP_SCRIPT_RUN_LOG}
fi

# 输入命令
if [ $# != 2 ] ; then 
	echo "Usage: $0 app_pro ai_pro"
	exit 1; 
fi 

# 程序路径
PROGRAM_PATH=/data/bin

# 程序名称
APP_EXE_NAME=${PROGRAM_PATH}/$1
AI_EXE_NAME=${PROGRAM_PATH}/$2

# 运行程序之前先清除log等数据
delete_script=delete_data.sh
if [ -f ${delete_script} ]; then
	echo "delete data..."
	source ${delete_script}
else
	echo "${delete_script} not exit!!!"
fi

# 启动http服务
thttpd -D -C /etc/thttpd.conf &

# 后台运行程序
nohup ${APP_EXE_NAME} &
app_run_result=$(ps -ef | grep -w ${APP_EXE_NAME} | grep -v grep | wc -l)
if [ ${app_run_result} -eq 1 ]; then
	echo "app_run_result = ${app_run_result}, ${APP_EXE_NAME} run success!!" >> ${APP_SCRIPT_RUN_LOG}
else
	echo "app_run_result = ${app_run_result}, ${APP_EXE_NAME} run error!!" >> ${APP_SCRIPT_RUN_LOG}
fi

nohup ${AI_EXE_NAME} &
ai_run_result=$(ps -ef | grep -w ${AI_EXE_NAME} | grep -v grep | wc -l)
if [ ${ai_run_result} -eq 1 ]; then
	echo "ai_run_result = ${ai_run_result}, ${AI_EXE_NAME} run success!!" >> ${APP_SCRIPT_RUN_LOG}
else
	echo "ai_run_result = ${ai_run_result}, ${AI_EXE_NAME} run error!!" >> ${APP_SCRIPT_RUN_LOG}
fi

# 程序重复运行了,杀死所有进程,重新执行脚本
if [ ${app_run_result} -gt 1 -o ${ai_run_result} -gt 1 ]; then
	killall_script=killall_pro.sh
	if [ -f ${killall_script} ]; then
		echo "kill all app pros..."
		source ${killall_script}
	else
		echo "${killall_script} not exit!!!"
	fi
	sleep 1
	source run_all_pros.sh
fi

平时开发过程中,有时候会挂着几个终端运行几个程序,有时候也需要一键后台运行所有程序。上面脚本可一键运行所有程序于后台,稍作修改可设置成开机自启动。

开机自启动相关内容可查看往期文章:干货 | 浅析程序开机自启动

5、一键杀死进程

#!/bin/bash

#####################################################################
# 脚本功能:一键杀死进程
#####################################################################

RELEASE_APP_NAME=app
RELEASE_AI_NAME=ai

release_app_run_result=$(ps -ef | grep ${RELEASE_APP_NAME} | grep -v grep | wc -l)
if [ ${release_app_run_result} -gt 0 ]; then
    killall -9 ${RELEASE_APP_NAME}*
	echo "kill ${RELEASE_APP_NAME}* success!!"
fi

release_ai_run_result=$(ps -ef | grep ${RELEASE_AI_NAME} | grep -v grep | wc -l)
if [ ${release_ai_run_result} -gt 0 ]; then
    killall -9 ${RELEASE_AI_NAME}*
	echo "kill ${RELEASE_AI_NAME}* success!!"
fi

http_run_result=$(ps -ef | grep -w thttpd | grep -v grep | wc -l)
if [ ${http_run_result} -gt 0 ]; then
    killall -9 thttpd
	echo "kill thttpd success!!"
fi

与上面的一键运行脚本相对应,一键杀死所有进程。

以上就是本次的分享~



文章作者: 杂烩君
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 杂烩君 !
  目录