关于Linux基础命令,可以查看另一篇博文 Linux Shell脚本攻略笔记
以下内容,主要是,了解书写shell脚本所需要的大部分知识,主要内容来自于书籍和网络
目的是,能快速书写出需要的shell脚本
开始
version 0.1 2014-01-12 基本内容, 完成度30%
资源
google shell style guide
Linux Shell脚本攻略笔记
Linux Shell编程实战技巧
Bash编程易犯的错误 1234
关于shell脚本编程的10个最佳实践
Bash Pitfalls
第一部分 一些概念
标准IO
文件描述符0 标准输入 默认键盘1 标准输出 默认终端2 标准错误 默认终端
重定向
> 输出重定向>> 追加到输出重定向< 输入重定向<< 追加到输入重定向ls -l > /tmp/acmd >/dev/null 2>&1 #输出到垃圾桶
管道
前后连接两个命令ls -l | grep test
引号
双引号:可以除了字符$`\外地任何字符或字符串单引号:忽略任何引用值,将引号里的所有字符作为一个字符串 $var 不能被解析反引号:设置系统命令输出到变量
shell脚本识别三种基本命令:内建命令,shell函数和外部命令
基本的命令查找:shell会沿着查找路径$PATH来寻找命令
echo $PATH可以在.profile文件中修改export PATH=$PATH:$HOME/bin
and/or
expression1 && expression2 && expression3只有前面一条命令执行成功,才执行下一条expression1执行成功,才执行expression2串联的expression1 || expression2 || expression3执行命令,直到有一条成功为止
第二部分 shell脚本
首行声明使用bash(声明脚本执行解释器)
#!/bin/bash# do somethingexit 0/n
运行
sh xx.shbash xx.sh #大部分情况下两个一样,某些命令只有bash有,只能用这个orchmod u+x xx.sh./xx.sh
调试
#查看运行时,每个命令回显,执行之后回显sh -x xx.sh#执行之前回显sh -v xx.sh#检查语法错误,不执行sh -n xx.sh#如果使用了未定义的变量,给出错误信息sh -u xx.sh#调试部分脚本echo "Hello $USER,"set -xecho "Today is $(date %Y-%m-%d)"set +x
判断执行结果
N=$? #0 <= N <= 2550 无错误,正常执行结束非0 异常 1-125命令不成功退出 126命令成功,但文件无法执行 127命令找不到 >128命令因收到信号而死亡
获取目录名和文件名
# To find base directoryAPP_ROOT=`dirname "$0"`# To find the file namefilename=`basename "$filepath"`# To find the file name without extensionfilename=`basename "$filepath" .html`e.g.BASEDIR=$(dirname $0)cd $BASEDIRCURRENT_DIR=`pwd`
日期
TODAY=`date +%Y%m%d`DAY_1_AGO=`date -d "$TODAY 1 days ago" +%Y%m%d`常用接受日期/使用默认日期处理if [ -n "$1" ]then TODAY="$1"else TODAY=`date +%Y%m%d`fi
crontab调度
查看crontab -l编辑crontab -e格式* * * * * command_path字段 含义 范围1 分钟 0-592 小时 0-233 日期 1-314 月份 1-125 星期几,0=周日 0-66 具体命令,可以是调用脚本*任意时刻n1,n2 分割,n1和n2*/n 每隔n单位n1-n2 时段,一个时段内0 */2 * * * sh run.sh 每隔两小时20 7 * * * sh run.sh 每天7:200 1,5 * * * sh run.sh 每天1点和5点* * * * * sh run.sh 每分钟执行一次
第三部分 变量1.变量赋值
varname="value"varname=`expression`注意,等号两边必须不能包含空格
2.分类
四种变量:环境变量、本地变量、位置变量、特定变量参数环境变量可作用于所有子进程本地变量在用户现在的shell 生命期的脚本中使用,仅存在于当前进程位置变量:作为程序参数特定变量:特殊作用
3.环境变量
设置MYVAR="test"expirt MYVARorexport MYVAR="test"只读MYVAR="test"readonly MYVARorreadonly MYVAR="test"显示export -penv #查看所有环境变量$MYVAR #获取消除unset MYVAR
4.本地变量
设置LOCAL_VAR="test"orLOCAL_VAR="test"readonly LOCAL_VAR #设置只读还可以使用declare命令定义
5.位置变量
$0 脚本名称$# 传递到脚本参数个数$$ shell脚本运行当前进程ID$? 退出状态$N N>=1,第n个参数
6.字符串处理
长度
${#VARIABLE_NAME} 可以给出字符串的长度。if [ ${#authy_api_key} != 32 ]then return $FAILfi
拼接字符串
echo "$x$y"
字符串切片
${变量名:起始:长度}得到子字符串$ test='I love china'$ echo ${test:5}e china$ echo ${test:5:10}e chinastr="hello world"echo ${str:6} # ${var:offset:length}
字符串替换
${变量/查找/替换值} 一个“/”表示替换第一个,”//”表示替换所有,当查找中出现了:”/”请加转义符”\/”表示echo ${str/foo/bar} #首个echo ${str//foo/bar} #所有
正则匹配
if [[ $str =~ [0-9]+\.[0-9]+ ]]
7.数值处理
自增
a=1a=`expr a + 1`ora=1let a++let a+=2
let
no1=4no2=5let result=no1+no2
expr
result=`expr 3 + 4`result=$(expr $no1 + 5)
其他
result=$[ no1 + no2 ]result=$[ $no + 5 ]result=$(( no1 + 5 ))
浮点数
echo "4 * 0.56" | bc设定精度echo "scale=2;3/8" | bc进制转换echo "obase=2;100" | bc平方echo "sqrt(100)" | bc
数组和map
第四部分 控制流1.条件测试
语法
test condition[ condition ] #注意两边加空格$? #获取判断结果,0表示condition=true
条件测试中的逻辑
-a 与-o 或! 非&&||if [ -n "$str" -a -f "$file" ]if [ -n "$str" ] && [ -f "$file" ]
字符串测试
= 两字符串相等!= 两字符串不等-z 空串 [zero]-n 非空串 [nozero][ -z "$EDITOR" ][ "$EDITOR" = "vi" ]
数值测试
-eq 数值相等(equal)-ne 不等(not equal)-gt A>B(greater than)-lt A<B(less than)-le A<=B(less、equal)-ge A>=B(greater、equal)N=130[ "$N" -eq 130 ]
文件测试
-d目录-f 普通文件(Regular file)-e 文件存在-z 文件长度=0-s 文件长度大于0,非空-b 块专用文件-c 字符专用文件-L 符号链接-r Readable(文件、目录可读)-w Writable(文件、目录可写)-x Executable(文件可执行、目录可浏览)-g 如果文件的set-group-id位被设置则结果为真-u 文件有suid位设置
2.分支if-else/case
if-else语法
if condition1then //do thing aelif condition2then //do thing belse //do thing cfiorif condition; then# do somethingfi
case语法
case $VAR in 1) echo "abc" ;; 2|3|4) echo "def" ;; *) echo "last" ;;esac
3.循环for/while/until
for语法
for VARIABLE in 1 2 3 4 5 .. Ndo //commandsdonefor OUTPUT in $(Linux-Or-Unix-Command-Here)do //commands on $OUTPUTdone#bashfor (( EXP1; EXP2; EXP3 ))do //commandsdone例子for i in 1 2 3 4 5; do echo $idonefor i in `seq 1 5`; do echo $idone#!/bin/bashecho "Bash version"for i in $(seq 1 2 20)do echo "Welcome $i times"donefor i in {1..5}; do echo $idone#!/bin/bashecho "Bash version"for i in {0..10..2}do echo "Welcome $i times"donefor ((i=1; i<=10; i++)); do echo $idone#无限循环#!/bin/bashfor (( ; ; ))do echo "infinite loops [ hit CTRL+C to stop]"done
while
while conditiondo //do somethingdoneCOUNTER=0while [ $COUNTER -lt 5 ]do COUNTER=`expr $COUNTER + 1` echo $COUNTERdone无限循环while [ 1 ]do //done
until
#执行命令,直到条件为真,至少执行一次,可以用来做监控,condition每次都回去检查until conditiondo //do somethingdone
break/continue
break允许跳出循环,通常在进行一些列处理后退出循环或case语句若多重循环,可指定跳出的循环个数,如跳出两重循环 break 2continue不会跳出循环,只是跳过此循环步命令是程序在本循体内忽略下面的语句,从循环头开始执行
第五部分 函数1.函数定义
function func_name() {}func_name() { //do some thing}
注意
函数名,在脚本中必须唯一函数必须,先定义,后使用
return
function equal() { return 1}equalecho $? #got 1
2.参数传递
#位置参数function copyfile() { cp $1 $2 return $?}调用copyfile /tmp/a /tmp/bor获取返回值result=`copyfile /tmp/a /tmp/b`
位置参数
$1 - $9,当参数超过10个时,需要使用${10}$# 参数个数$* 将所有参数视为一个字符串="$1 $2 ..."$@ 将所有参数视为个体="$1" "$2" "$3"
3.返回值和退出状态
#返回值function func_a() { return 1}result=`func_a`if [ result != 0 ]then echo "Error"fi#退出状态function func_b() { //do something}func_bif [ $? -eq 0 ]then echo "Success"else echo "Error"fi#更简洁if func_b; then echo "Success"else echo "Error"fifunc_b && echo "Success" || echo "Error"
第四部分 高级
bash中参数展开-展开运算符
${varname:-word} 如果变量未定义,返回默认值. ${noexist:-0}返回0${varname:=word} 如果变量未定义,设置变量为默认值 ${noexists:=0}; echo ${noexists}; 得到0${varname:?message} 若未定义,显示varname:message并退出当前的命令或脚本${varname:+word} 若存在且非null,返回word,否则返回null
模式匹配
${variable##pattern}${variable%pattern}
第五部分 其他
读文件
while read -r line; do echo $linedone < file保留首尾字符while IFS= reaad -r line; do echo $linedone
一些内置命令
:空命令,类似python的pass.相当于source\用于跨行命令echo输出,类似printlnexecexit n脚本以n作为退出码退出export设置或显示环境变量expr简单计算x=`expr $x + 1`x=$(expr $x + 1)letd=111let d=$d+1; echo $d112printf格式化输出return函数返回setshift所有参数变量左移一个位置unset从环境变量中删除变量或函数
BP:
使用$() 代替反引号``$(()) 代替expr运算符
bash
GNU Bash 主页http://www.gnu.org/software/bash/GNU Bash 手册http://www.gnu.org/software/bash/manual/
更多的特性
$((3 + 4)) 而不需要 expr 3 + 4, 算术展开/usr/{bin,local/bin} 而不需要 /usr/bin /usr/local/bin${str/src/dst} 而不需要 echo $str | sed ”s/$src/$dst/”
更方便的语法
for (( expr1; expr2; expr3 )); do commandsdonefor (( i = 0; i < 100; i++ )); do … doneecho a{b,c,d}e ==> abe ace ade
表达式求值
$[] []$中间可以加表达式 eg: echo $[$a+$b]$(()) (())中间可以加表达式。Eg: total=$(($a*$b))
正则
bash的正则表达式str='hello, world'if [[ $str =~ '\s+world$' ]]; then echo match!fiif echo "$str" | grep -E '[ ]+world$'; then echo match!fi
获取软连接指向的真实文件名
#注:有些系统没有这个命令readlink /usr/bin/python
增加debug
function debug() { if [[ $DEBUG ]] then echo ">>> $*" fi}# For any debug messagedebug "Trying to find config file"还有来自于一些很酷的Geeks的单行debug函数:function debug() { ((DEBUG)) && echo ">>> $*"; }function debug() { [ "$DEBUG" ] && echo ">>> $*"; }
将执行日志全部写到某个文件