Shell编程常用知识

1、给数值型变量赋值,需要保证变量的值为数值型,避免后续处理中出现异常。

count=`cat app.log | wc 1`
isNumber()
{
    if[[ "$1" -eq "$1" ]; then true
    else
    echo " [$1] isn't a number"
    exit 1
    fi
}
isNumber $count

2、使用ps命令筛选进程时,如能确定进程所属用户,必须在参数中指定用户名称,如其输出作为kill命令的输入,则必须指定进程所属用户,如:

kill -9 `ps -fu $USERNAME|grep java| grep AdminServer`

3、脚本的“并发锁”控制

shell编程并没有其他语言具备的良好的多线程的控制能力,可以通过简单的“加锁机制”实现并发控制。创建一个锁文件,通过判断锁文件是否存在实现并发控制。简单实现:

#!/bin/bash
SHELL_LOG="${SHELL_DIR}/S{SHELL_NAME}.log"
LOCK_FILE="/home/sysadmin/scripts/shell/${SHELL_NAME).lock"
shell_log() {
    LOG_INFO=$1
    echo "$(date "+%Y-%m-%d") $(date“+%H-%M-%5") : ${SHEL_NAME}: ${LOG_INFO)">>S{SHELL _LOG}
}
 
shell_usage(){
    echo $"USAGE:$0 {backup}"
}
 
####增加shell_lock()函数,用于touch一个文件,作为文件锁
shell_ lock(){
    touch ${LOCK_ FILE}
}
 
###增加shell_unlock()函数,用于删除创建的锁文件
shell_ unlock(){
    rm -f ${LOCK_ FILE}
}
 
### shell _do()函数需要判断是否存在LOCK_ FILE, 若存在说明有用户正执行,此时提示信息,并退出程序,
###若不存在在文件LOCK_FILE,则执行shell_lock创建锁文件,sleep10秒,模拟执行,结束前执行shell_unlock,删除锁文件完成,此时其他用户可以执行。
shell_do(){
    if[ -f "${LOCK_ FILE}" ]; then
    	shell_log "${SHELL_NAME} is running"
    	echo "${SHELL_NAME}" is running && exit
    fi
    shell_log "shell_start"
    shell_lock
    sleep 10
    shell_log "shell_lock"
    shell_unlock
}
 
main(){
    case $1 in
      start)
          shell do
          ;;
      *)
          shell _usage;
      esac
}
main $1

4、控制脚本不退出的风险,周期频繁执行的脚本,需要防止脚本挂死不退出,而后续脚本忽略此异常状态继续执行。所以在执行前进行脚本进程唯一性检查。

#脚本唯-一性检查,判断脚本没有退出,即不再执行。
pslisftile=${TMP_ PATH}/pslstile.logicalserver.tmp
scriptname=Linux_SMDB_Scripts
ps -ef | grep ${scriptname} > ${pslisftile}
pnum= `cat ${pslisftile} | grep ${scriptname} | grep-v grep | wc -l`
if[ $pnum -ge 1 ]; then
	echo "The old ${scriptname} is hang!!"" >> ${script_output_result}
	exit 1
fi

5、频繁追加文件防止无限制增长的风险,向一个文件中追加数据时,一定要设置文件大小的阈值,必要时清空,避免文件无限增大。尤其是对日志文件进行类似处理。

#举例,当数据文件超过1Mb=1048576或者15Mb=1572864字节时,将数据文件清空,防止数据文件无限增长
if[-f ${capacityinfo} ];then
	#如果文件大于1M就将RT CAPACITY.txt清空,防止文件无限增长
	filesize='ls -l ${capacityinfo} | awk '{print $5}'`
	if[ $filesize -ge 1048576 ];then
		cat ${capacityinfo} >> ${capacityinfo bak}
		cat /dev/null> ${capacityinfo}
	fi
else
	cat /dev/nul > ${capacityinfo}
fi

一般情况下,需要对频繁追加内容文件的目录设置清理过期文件策略,避免产生的文件越来越多,造成文件节点用尽。极端情况,目录中的文件过多,删除目录文件时,可能会报参数太长错误无法删除,建议放在循环中遍历删除:

for i in `ls /backup__databak/bak_ tar/*.tar`
do
	test -f "${i}" && rm-f "${i}"
	#每次循环遍历,确认后删除
done

6、复制文件时尽量避免使用cp,使用重定向>代替:

使用>修改和回退文件时,保留原文件的属组和权限,避免使用cp时权限属组被修改。

cat a.txt.bak >a.txt,避免使用cp a.txt.bak a.txt
sed -e 's/aaaccc/g'a.txt > a.txt.tmp
cat a.txt.tmp >a.txt

7、for循环的坑:

for循环的in条件按空格来区分,忽略此规则容易进入不正确或死循环。

for i in `ls*.txt`; do... ; done
#错误写法,因为for..in语句是按照空格来分词的,包含空格的文件名会被拆成多个词。
#正确写法:
for i in * . txt; do ... ; done

8、while循环的禁忌,如果还想使用循环中的变量,while不能结合管道使用。

因为管道中的语句都放到一个新的子shell中执行,所以子shell中定义的变量无法传递出来,循环结束变量释放,循环外无法引用。

9、慎用cp:

同样有空格分词的问题。所以应当用双引号。

cp "$file" "$target"

但是如果凑巧文件名以 - 开头,这个文件名会被 cp 当作命令行选项来处理。

可以试试下面这个:

"$file" "$target" --cp

但也可能再碰上一个不支持 -- 选项的系统,所以最好用下面的方法:

for i in./*.txt; do cp "$i" /target

10、慎用cd:

避免使用cd到操作目录再操作的方式,可能导致进入目录失败,误删除

cd /app/logbak
rm 20??????.tar
# 当cd没有成功时,会删除当前目录下的匹配成功的文件,造成误删

当然也可以通过判断cd命令的返回值,避免类似问题的发生

cd /dir && test 	 		# 根据cd返回值执行单条命令用法
cd /dir || exit1; test 		# 根据cd返回值执行多条命令用法

还有一种情况,如果你要在shell程序中频繁变换工作目录,如下面的代码:

find ... -type d | while read subdir; do cd "$subdir" &&... && cd -done

最好写成这样,括号会强制启动一个子shell,这样在这个子shell中改变工作目录不会影响父shell(执行这个脚本的shell),就可以省掉cd - 的麻烦。

find .. -type d | while read subdir; do (cd "$subdir" && .. && .. done &&…) done&&…) done &…) done
cd - done

11、用[[ ]]代替[]

[ $var="var" ]

当$var为空时,上面的命令就变成了[ ="bar" ],类似地,当$var包含空格时:[ space words here = "var" ]两者都会出错。所以应当用双引号将变量括起来:

[ "$var" = var ] 几乎完美了。

但是,当$var以 - 开头时依然会有问题。在较新的bash中你可以用下面的方法来代替,[[ ]]关键字能正确处理空白、空格、带横线等问题。

正确的:  [[ $var=var ]] (注意有空格)

另注意,[[]]适用于字符串,如果是数值,要用如:(( $var > 8 ))

12、管道操作中不要同时操作文件

cat file | sed “s/old/new/g" > file

你不能在同一条管道操作中同时读写一个文件。根据管道的实现方式,file要么被截断成0字节,要么会无限增长直到填满整个硬盘。如果想改变原文件的内容,只能先将输出写到临时文件中(tmpfile),再用mv命令到目标文件。

sed 's/old/new/g' file > tmpfile && mv tmpfile file
posted @ 2020-10-11 23:13  一介草民李八千  阅读(191)  评论(0)    收藏  举报