作为一个 Java 程序员,Go 爱好者,自然免不了天天和 Linux 打交道,也曾经写过一点点 shell 脚本,但是对那个反人类的语法深感厌恶,空格不对都不行。无奈项目需要一定要用 shell 来实现一个工具,学习的过程总是不那么顺风的,不过搞完之后也觉得没那么讨厌了。整理一下几天所得,希望能让一个从没写过 shell 但是还挺熟悉 Linux 的可以立马完成一个可用的脚本。
- 执行顺序
脚本顺序执行,原来怎么敲命令的就怎么写
-
变量赋值
# 变量赋值时等号两边不能有空格 # 单引号是固定字符串 pa='string' # 双引号可包含变量 pb="ps is ${pa}" # 接受命令返回 pc=`ls -alh`
-
数组及其遍历
arr=(aa bb cc dd ff) # 通过下标访问 for ((i=0; i<5; i++)) do echo "$i: ${arr[$i]}" done # 遍历访问 for s in ${arr[@]} do echo " $s" done # 空格分隔的字符串也能遍历,但是不能像上面的方式一样用下标访问元素 arr2='a1 a2 a3 a4 a5' for s in ${arr2} do echo ${s} done
-
条件判断
# shell 脚本都是指令,if 的语句一定要注意空格 # 第一种写法,下面输出 ok if [[ 10 -gt 3 ]]; then echo ok; else echo no; fi # 第二种, ** 注意(): 下面输出 ok if [ 2 > 3 ]; then echo ok fi # 第三种, 下面输出 no if [[ 2 > 3 ]] then echo ok else echo no fi
-
定义函数
res=0 echo $res add() { ((res = $1 + $2)) } add 12 13 echo $res
-
$?
说明# $?接受的是上一条命令执行后的返回值 ls /home # 下面的输出是 0 echo $? testReurn() { return 8 } testReurn # 下面的输出是 8 echo $?
-
字符串操作
a='stringA' b='stringB' # 判断是否相等,下面输出 no if [[ $a == $b ]]; then echo yes; else echo no; fi # 字符串拼接, 下面输出 yes if [[ 'stringAstringB' == "${a}${b}" ]]; then echo yes; fi # 取字符串长度, 下面输出 7 echo ${#a} # 截取字符串, 下面输出 string, ing echo "${a:0:6}, ${a:3:3}" # 判断两个字符串是否有相同前缀, 下面输出 yes if [[ ${a:0:5} == ${b:0:5} ]]; then echo yes; else echo no; fi # 字符串切分为数组, IFS 变量指定分隔符, 分隔符前后空格会被略去 IFS=, read -r -a arr <<< 'a,b ,c, d,g e, ss' for str in ${arr[@]}; do echo "'${str}'"; done
-
文件和目录判断
if [[ -f $filename ]]; then echo "$filename 是一个文件" elif [[ -d $filename ]]; then echo "$filename 是一个目录" elif [[ -p $filename ]]; then echo "$filename 是一个管道文件" elif [[ -S $filename ]]; then echo "$filename 是一个 sokcet 文件" elif [[ -b $filename ]]; then echo "$filename 是 block device" elif [[ -c $filename ]]; then echo "$filename 是 character device" fi if [[ -L $filename ]]; then echo "$filename 是一个软链接" fi # 对于软链接,使用-L测试时,当链接指向的目标文件不存在时会返回false if [[ -L $filename || -e $filename ]]; then echo "$filename 存在 (可能是失效的链接)" fi if [[ -L $filename && ! -e $filename ]]; then echo "$filename 是失效的软链接" fi
-
内容既输出到控制台也输出到文件里
echo 'ok'| tee -a bb.log
-
处理退出信号
trap "rm -f ${lock_file}; echo 'exited ok.'" SIGINT SIGQUIT # SIGHUP:从终端终止或退出正在前台运行的进程 # SIGINT:从键盘按下 Ctrl-C # SIGQUIT:从键盘按下 Ctrl-\ # SIGTERM :软件终止信号
-
处理参数
if [[ "$OSTYPE" == "darwin"* ]]; then # Mac OSX ( brew install gnu-getopt ) getopt_cmd="$(brew --prefix gnu-getopt)/bin/getopt" else # linux-gnu getopt_cmd="getopt" fi long_opts="once,name:,note:" opts=$($getopt_cmd -n $0 -o - --long $long_opts -- "$@") eval set -- "$opts" while : do case "$1" in --once) once="true" ; shift 1 ;; --name) name=$2 ; shift 2 ;; --note) note=$2 ; shift 2 ;; --) shift ; break ;; *) echo "参数错误" ; exit 1 ;; esac done echo "once: ${once:-no}, name: ${name}, note: ${note}"
-
MySQL 查询
std_log='/var/log/test.log' err_log='/var/log/test.err.log' user='root' pwd='' host='127.0.0.1' db='mysql' exec_sql() { echo "exec_sql: $1" | tee -a ${std_log} mysql -u${user} -p${pwd} -h${host} -D${db} -s -N -e "$1" | tee -a ${std_log} } exec_sql "show databases"
标准输入输出重定向
shell中,每个进程都和三个系统文
件相关联:标准输入stdin,标准输出stdout和标准错误stderr,三个系统文件的文件描述符分别为0, 1, 2
在使用 mysql 命令获取结果时会有一些警告信息
mysql: [Warning] Using a password on the command line interface can be insecure.
但是我要得到命令的结果不需要这些警告, 这个时候就需要重定向错误输出到其他地方
num=`mysql -u${user} -p${pwd} -h${host} -D${db} -s -N -e "${count_sql}" 2>${err_log}
注意
此为个人这一周以来的小总结,并非专业的 shell 教程,旨在能帮助懂编程的人不会 shell 的能快速上手,少走一些我趟过的坑,减少一些搜索。
有些原理我也不是太清楚,以后需要的时候才会去系统学习吧,现在这些已经能完成任务了。