hello world!
#! /bin/bash
echo “hello world!”

$ chmod +x a.sh
$ ./a.sh
hello world!



变量
 变量不分类型 (没有int,char,string)
 不需要声明,直接使用
 赋值:name=value (左右两边不能有空格)
 使用:$name ${name}

 foo=h
 echo ${foo}ello


变量的作用域
默认全局作用域(仅当前shell可见)
 local 限定函数局部变量
 function a() { local msg; }
 使用export导出变量,让子shell可以继承
 export var=1
 source 或 .(dot) 在当前shell下执行脚本
 source ./config.sh


变量分类
 自定义变量
 环境变量 (set命名可查看)
 $PATH,$IFS,$PS1,$PWD,$LINENO
 位置参数(Positional Parameters)
 $1 $2 $3 … ${10}
 特殊参数(Special Parameters)
 $#:位置参数的数量 
 $*:所有位置参数的内容 ($1 $2 …)
 $@: 所有位置参数的内容(“$1” “$2” … )
 $?:命令执行后返回的状态
 $$:当前进程的进程号 
 $!:后台运行的最后一个进程号
 $0:当前执行的进程名


玩转变量
 使用eval实现变量的间接引用
 x='abc def'
 y='$x'
 echo $y
 $x
 eval echo $y
 abc de




玩转变量(续)
 ${!p} #双重引用
 a=1
 b='a'
 echo ${!b}
 1
 ${!p*} #返回所有以p开头的变量 
 echo ${!P*}
 PATH PIPESTATUS PPID PS1 PS2 PS4 PWD
 ${p:-word} #如果变量p不存在,返回"word”
 ${p:=word} #如果变量p不存在,返回"word",并将p的值设为"word"
 ${p:?word} #如果变量p不存在,将"word"打入STDERR 
 ${p:+word} #如果变量p存在,返回"word" 


玩转变量(续)
 if [${ret:=1} -ne 0 ]
 then
 echo “NO”
 exit
 fi



引号迷雾
 双引号
 使用双引号可解释$符号,反引号和反斜线等特殊字符
 echo “$msg” => 显示msg变量值
单引号
 与双引号类似,不同的是shell会忽略任何特殊符号
 echo ‘$msg’ => 显示$msg 
 反斜杆
 \c == ‘c’
 反引号(命令替换) 
 用于执行系统命令并输出到变量
 echo The date and time is `date`  


几种括号
 (list) list将在一个子shell中执行, 不会对当前shell产生影响,返回list的exit值
 { list; } 可以作组合命令用,list将在当前shell中被执行,list结尾处必须要有新行或‘;’号,返回list的exit值,list前后必须有空格 
 ((expression)) 算术计算 
 [ ] [[ ]] 分支测试


数组
 name=(value1 ... valuen) 此时下标从0开始
 name[index]=value
 unset name 或 name=

 数组下标的范围没有任何限制,同时也不必使用连续的分量
 $ A=(a b c def)
 $ A[3]=bb

 $ echo ${A[0]} #取第一个元素
 a
 $ echo ${A[@]} # 取全部元素
 a b c def
 $ echo ${#A[@]} # 取得数组元素的个数
 4 



数组(续)
 遍历数组:
 total=${#A[*]}
 for ((i = 0; i < total; i++))
 do
 echo ${A[$i]}
 done



分支语句
 if list; then command; 
 [ elif list; then command; ] ... 
 [ else command; ]
 fi
 case $word in
 [a-z]) list ;;
 *) default;;
 esac
 [ $# -eq 1 ] && slen=1 || slen=0



条件测试
 对文件、字符串和数字使用test命令。test一般有两种格式:
 test condition 或 [ condition ](注意空格)
 if [ $str = “a.txt” ];then 
 echo “OK"
 fi
 直接测试命令:
 if grep abc a.txt &>/dev/null;then
 echo “Bingo!”
 fi




条件测试(续)
 推荐使用[[ ]]进行条件测试
 if [[ “x$str”== “xa.txt” && -f b.txt ]]
 then
 cmd;
 fi
 -f -d -z ……
 man bash
 CONDITIONAL EXPRESSIONS



 条件测试 – 数值比较
 if [ $a –lt 0 ]
 then
 echo OK
 fi

 推荐使用(( ))
 if (( a > 0 ))
 then
 echo OK
 fi



循环语句
 for name [ in word ] ; do list ; done
 for i in `ls *.result`;do cat $i; done

 for (( expr1 ; expr2 ; expr3 )) ; do list ;done
 for ((i=0;i<100;i++));do echo $i;done

 while list; do list; done
 while read line
 do
 echo $line
 done < a.txt
 until list; do list; done



注释
 # 行注释 (#前要有空格)
 echo $msg #print message

 块注释
 :<<COMMENT
 echo $msg
 COMMENT

 comment()
 {
 echo $msg
 }


正则表达式基础
 元字符
 . 匹配任何单个字符。
  $ 匹配行结束符。^ 匹配一行的开始。
 * 匹配0或多个正好在它之前的那个字符。
 + 匹配1或多个正好在它之前的那个字符。
 ? 匹配0或1个正好在它之前的那个字符。
 \{i\} \{i,j\} 匹配指定数目的字符。
 \ 这是引用符,转义;
 [ ]  [c1-c2] 匹配括号中的任何一个字符。 [^c1-c2] 
 \< \> 匹配词(word)的开始(\<)和结束(\>)。
 \( \) 将 \( 和 \) 之间的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用。
 | 将 两个匹配条件进行逻辑“或”(Or)运算。例如正则表达式(him|her) 



正则表达式举例
 HTML标签
 <[^>]*> 

 匹配由26个英文字母组成的字符串 
 ^[A-Za-z]+$
   
 Email地址
 \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* 

 URL
 [a-zA-z]+://[^\s]*



管道和重定向
 管道可以把一条命令的输出作为另一条命令的输入
 Command1 | Command2
 返回值是最后一个命令的返回值

 重定向
 wc –l /etc/passwd > a.txt
 wc –l /etc/passwd >> a.txt
 wc –l < /etc/passwd
 ./command > a.txt 2>&1 (./command &> a.txt)

 exec 5<> a.txt
 echo “hello” >&5
 <&- 
 >&-


作业控制
 <CTRL-Z> 将当前任务挂起,返回job_id
 fg job_id 把后台作业放到前台执行
 bg job_id 把作业放到后台执行

 vi b.sh
 <CTRL-Z>
 [1]+ Stopped vim b.sh
 bg 1
 [1]+ vim b.sh &
 fg 1
 vim b.sh


自定义函数
 function foo() # foo为函数名
 {
 local a=$1; # 局部变量

 echo $a;
 return 0; # 返回值
 }

 foo “cool!” # 函数调用
 echo $? # 打印返回值



 自定义函数 – 16进制转点分十进制
 a()
 {
        local str=$1
        echo -n $((16#${str:0:2}))
        str=${str:2}
        if [ "x$str" = "x" ]
        then
               echo; return
        else
               echo -n "."; a $str
        fi
 }
 #Usage
 a "DDB14CCF"


整数计算
 id++ id-- ++id –id - + ! ~ ** * / % 计算
 << >> & ^ | 位操作
 <= >= < > == != 比较
 && || 逻辑操作
 expr?expr:expr 三元操作符
 = *= /= %= += -= <<= >>= &= ^= |= 赋值操作符

 y=2000 闰年计算
 echo  $((y%4==0 && y%100!=0 || y%400==0)) 
 (( y++ )) 自增1
 tmp=$((16#a)) 进制转换


浮点运算
 echo “scale=5; 3/7"|bc –l
 .42857
 echo "100.43KB 20.12KB" | awk '{print $1-$2}'
 80.31
 echo "ibase=16;F"|bc -l 
 15




简单字符串处理
 x=abcd
 ${#x} # 获取字串长度
 4
 expr index  $x “b“ # 获取子串所在偏移
 2expr index  $x "a“ # 获取子串所在偏移
 1 
 echo ${x:1} # 获取子串
 bcdecho ${x:2}cdecho ${x:0:2} 
 ab



 简单的字符串处理(续)
 x=aabbaarealwwvvwwecho “${x%w*w}“ # 截去尾部最短匹配
 aabbaarealwwvvecho “${x%%w*w}“ # 截去尾部最长匹配
 aabbaarealecho “${x##a*a}“ # 截去头部最长匹配
 lwwvvwwecho “${x#a*a}“ # 截去头部最短匹配
 bbaarealwwvvww 

 x=abcdabcdecho ${x/a/b} # 只替换一个bbcdabcdecho ${x//a/b} # 替换所有bbcdbbcd


 简单字符串处理 – 实际应用
 截去域名尾部
 name=jx-sys-superdb.jx.baidu.com
 echo ${name%%.*} 
 jx-sys-superdb

 截取日期
 str=20081011
 year=${str:0:4} 

 替换
 echo ${name//jx/tc}
 tc-sys-superdb.tc.baidu.com


 随机字符串生成
 typeset -r DEFAULT_STR_LEN=5
 typeset -ra dict=(a b c d e f g h i j k l m n o p q r s t u v w x y z)

 function get_random_letter()
 {
 echo -n ${dict[$((RANDOM%${#dict[*]}))]}
 return 0
 }

 function get_random_string()
 {
 local slen str

 [ $# -eq 1 ] && slen=$1 || slen=$DEFAULT_STR_LEN

 for ((i = 0; i < slen; i++))
 do
 str=${str}`get_random_letter`
 done

 echo $str
 return 0
 }

 get_random_string $1


 调试
 -x
 -n 是只语法检查而不执行任何命令
 -e 是脚本发生第一个错误时就中止脚本运行,即当一个命令返回非零值时退出脚本 (除了until 或 while loops, if-tests, list constructs)
 --posix 是更改Bash或脚本的行为,使之符合POSIX标准
 Shell 伪信号:EXIT,ERR,DEBUG


 调试(续)
 + typeset -r DEFAULT_STR_LEN=5
 + typeset -ra 'dict=(a b c d e f g h i j k l m n o p q r s t u v w x y z)'
 + get_random_string 2
 + local slen str
 + '[' 1 -eq 1 ']'
 + slen=2
 + (( i = 0 ))
 + (( i < slen ))
 ++ get_random_letter
 ++ echo -n t
 ++ return 0
 + str=t
 + (( i++ ))
 + (( i < slen ))
 ++ get_random_letter
 ++ echo -n k
 ++ return 0
 + str=tk
 + (( i++ ))
 + (( i < slen ))
 + echo tk
 tk
 + return 0

 信号捕获
 #!/bin/bash

 trap "print_OK" 3

 function print_OK()
 {
 echo OK
 }

 while :
 do
 :
 done

 发送信号:kill -3 pid

 屏蔽信号:trap “” 3


 其他常用内置命令
 exec command #用command替换当前进程
 type ls
 ls is aliased to `ls --color=tty`
 : 空命令
 while :
 do
 cmd
 done

 if [ list ]; then : ;else echo false;fi


 常用工具
 编辑软件: vi,emacs
 联机帮助:man, info
 查找类:find,locate,which,whereis,whatis
 文本处理类:uniq,cut,paste,join,sort,comm,diff
 二进制文件读取类:od,xxd,dd,hexdump
 文本分析类:grep,sed,awk
 系统状态类:top,ps,pstree,pgrep,/proc,strace,vmstat,netstat
 传输类:wget



 Grep - 全文匹配利器
 --color 飘红匹配到的部分
 -i 忽略大小写
 -v 反向匹配
 -r 递归匹配文件
 -o 只打印匹配到的部分
 -n 打印出行号
 -c 统计匹配到的行数
 -w 匹配整词

 grep "sort“ *.doc 

 Awk – 文本处理利器
 awk命令的一般形式: awk ' BEGIN { actions } pattern1 { actions } ............ patternN { actions } END { actions } ‘
 awk -F: '{print $1} END{print "total:",NR}' /etc/passwd 



 Awk – 文本处理利器 (续)
 取机器序列号
 dmidecode|awk '/Serial Number:/{print $NF;exit}‘

 统计词频
 awk '{a[$0]++}END{for(i in a){print i,a[i]}}' a.txt

 类似uniq功能
 awk '! a[$0]++' a.txt



 Awk – 文本处理利器 (续)
 杨辉三角
 #!/usr/bin/awk -fBEGIN {         yan[1,0] = 1;         for (i = 2; i <= int(ARGV[1]); i++)         {                 yan[i,0] = 1;                 yan[i,i-1] = 1;                                 for (j = i-2; j > 0; j--)                         yan[i,j] = yan[i-1,j-1] + yan[i-1,j]         }                 # output         for (i = 1; i <= int(ARGV[1]); i++)         {                 for (j = 0; j < i; j++)                         printf("%d ", yan[i,j]);                 print         }}
 #Usage:
 #     $ ./test.awk 10


 head,tail
 功能:取一个文件的头若干行或者尾部的若干行。
 常用选项:
 -n num:指定选取的行数
 -f:tail的选项,定时输出文件的最后若干行。
 使用举例
 tail和head常用来分析日志或者对大规模数据抽取一小部分
 tail –f example.log
 watch -n 1 head url.lst 



 diff,cmp,diff3,sdiff,comm
 功能:
 diff:按行比较两个文件的不同
 cmp:按字节比较两个文件的不同
 diff3:按行比较三个文件的不同
 sdiff:输出两个文件的合集。输出文件中两个文件原本的行在同一行中不同列
 comm:快速的比较两个已经排过序的文件,输出两个文件的合集,交集,或任何单独的部分



 diff常用选项
 常用选项。主要介绍diff的各个选项
 -b 忽略两行行尾空格,以及空格个数的区别
 -E 忽略tab和空格间的区别
 -w 完全忽略所有空格类字符
 -B 忽略空行
 -I 忽略大小写
 --normal以normal形式输出不同行。即指输出不同的行
 -c 以context形式输出不同行。包含不同行的上下文



 find,locate
 功能:查找文件。find将在目录树中查找和用户指定模式相符合的文件。locate则是通过在locate的数据库中查找,locate 的数据库由updatedb程序负责维护。
 常用选项:
 -name:指定要查找的文件名
 -perm:指定要查找文件的权限
 -size:指定要查找文件的大小范围
 -mtime:指定查找修改时间在n天以内的文件。
 exec command:将find命令查找到的文件作为command命令的参数
 使用举例:
 find . -mtime –1:查找在最近一天内被修改的文件
 find . -name b.cpp -exec mv \{\} a.cpp \;





 sort
 功能:对文件中的各行进行排序。
 sort排序是根据从输入行抽取的一个或多个关键字进行比较来完成的。缺省情况下以整行为关键字按ASCII字符顺序进行排序。
 常用选项
 - m 若给定文件已排好序,合并文件。
 - c 检查给定文件是否已排好序。
 - u 对排序后认为相同的行只留其中一行。
 - d 按字典顺序排序,仅比较字母、数字、空格和制表符。
 - r 按逆序输出排序结果。
 - b 在每行中寻找排序关键字时忽略前导的空格和制表符。
 - t separator 指定字符separator作为字段分隔符。
 -k,pos1,[pos2]:以pos1到pos2中间的字符为键值
 使用举例
 cat words | uniq –c | sort –k 1,1 –n –r 将一批词按照出现频次有高到低排序



 uniq,join,cut,paste
 cut功能:用来从标准输入或文本中剪切指定列或者域
 常用选项:
 -c:指定剪切字符数
 -f:field 指定剪切指定域数
 -d:delimit 指定除空格和tab外的域分隔符
 使用举例:
 cut –d : -f 3 example.txt
 who –u|cut –c1-8
 paste功能:将两个文件按行粘贴在不同的列中。是cut的反向操作。



 dd
 拷贝二进制文件,
 格式:
 count=BLOCKS 只拷贝BLOCKS个数据块
 ibs=BYTES 一次读入的数据量
 if=FILE 输入文件
 obs=BYTES 一次写出的数据量
 of=FILE 输出文件
 seek=BLOCKS 输出文件跳过BLOCKS个数据块
 skip=BLOCKS 输入文件跳过BLOCKS个数据块

 time dd if=/dev/zero of=test bs=1024k count=1024 查看系统io性能


 wget
 功能:支持使用FTP和HTTP协议,从其他主机上下载所需要的文件
 常用选项:
 -r:递归的下载目录以及它的子目录和所有文件
 -nH:不创建以目标主机域名为目录名的目录,将目标主机的目录结构直接下到当前目录下
 --cut-dir=[number]不在本地机器上建立的目录层数
 -m, --mirror自动开启适合用来镜像站点的选项 
 -A, --accept=LIST允许下载的文件类型列表
 -R, --reject=LIST拒绝继续下载的文件类型列表
 -D, --domains=LIST允许继续扩展的站点列表
 --tries=[number]自动重连的次数 
 -c:断点续传 
 --debug:使用这个选项可以看到更多wget下载文件过程中的调试信息,比如下载一个http文件时所发送和接收的http包头的格式
 --timeout=SECONDS控制wget读超时时间,缺省为900秒
 Wget –nH –cut-dir=1 ftp://*:*@test.baidu.com/
 wget “http://www.sina.com”




 参考资料
 Man
 正则表达式之道
 Sed与awk
 Advanced Bash-Scripting Guide