使用多个命令(;):
如果需要两个或多个命令一起执行,用分号把这些命令隔开;
#date ; ifconfig eth0
Sat Nov 1 08:47:46 CST 2014
eth0 Link encap:Ethernet HWaddr 00:50:56:9F:22:36
inet addr:192.168.57.23 Bcast:192.168.57.255 Mask:255.255.255.0
inet6 addr: fe80::250:56ff:fe9f:2236/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1785133 errors:13 dropped:13 overruns:0 frame:0
TX packets:1707231 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:245612681 (234.2 MiB) TX bytes:1915997555 (1.7 GiB)
Interrupt:18 Base address:0x2000
2. 显示文本(echo):
echo的命令格式:
echo [option] [STRING]
option:
-n: 不打印换行符
-e: 启用转义符
-E:禁用转义符(缺省设置)
-e选项可以使用的转义字符:
\\: 反斜杠
\a: 响铃
\b: 退格键
\n: 换行符
\t: 水平制表符
\v: 垂直制表符
\0NNN:
\033[##n:
第一个#:3表示前景色
4表示背景色
第二个#:颜色,1-7
\033[0m:控制符结束
#echo -e "\033[31mHello World\033[0m"
Hello World
3. 变量
变量的类型:
本地变量: 只对当前shell有效,对其子shell以及其它shell都无效;
定义变量:[set] Var_Name="Value"
引用变量: $Var_Name
撤消变量: unset Var_Name
局部变量:仅对局部代码有效
local Var_Name="Value"
环境变量:
全局环境变量:对当前shell及其子shell有效;
printenv: 查看全局环境变量
export Var_Name="Value" 设置全局环境变量
局部环境变量:只对创建它们的shell有效;
set: 查看局部环境变量;
Var_Name="Value" 设置局部环境变量
PS1: 控制默认命令提示符的格式
PS2: 控制后续命令行提示符的格式
echo $PS1
[\u@\h \W]\$
echo $PS2
>
在提示符中使用的特殊字符总结:
\a: 报警字符
\d: "日月年"格式显示的日期
\e: ASCII转义字符
\h: 本地主机名
\H: 完全限定域名(FQDN)
\j: shell当前管理的任务数
\l: shell终端设备中的基名
\n: ASCII换行符
\r: ASCII回车符
\t: 24小时制HH:MM:SS格式的当前时间
\T: 12小时制的当前时间
\@: 12小时制am/pm格式的当前时间
\u: 当前用户的用户名
\v: bash shell的版本
\V: bash shell的发行版本
\w: 当前工作目录
\W: 当前工作目录的基名
\!: 这个命令在bash shell历史记录中的位置
\#: 这个命令在当前命令行的位置
\$: 普通用户下的$,root用户下的#
\nnn: 与八进制数nnn对应的字符
\\: 反斜线\
\[: 开始一个控制字符序列
\]: 结束一个控制字符序列
位置变量:
$1 $2 ... $n
./first.sh 1 2
$1:1
$2:2
特殊变量:
$0: 脚本名称自身
$?: 上一条命令的执行状态;
状态用数字来表示: 0 - 255
0: 表示命令执行成功
1-255:表示命令执行失败
$#: 位置参数的个数
$@:引用所有的位置参数
$*:引用所有的位置参数
4. 反引号(``):用于引用命令命令执行的结果
#date_now=`date`
#echo $date_now
Sat Nov 1 09:27:04 CST 2014
5. 输入输出重定向
标准输入:stdin-->0
标准输出:stdout-->1
标准错误: stderr-->2
输入重定向:
<: 输入重定向:
<< EOF:用于在脚本中创建文件或生成菜单
输出重定向:
>: 覆盖输出
>>: 追加输出
set -C: 禁止使用覆盖重定向至已经存在的文件;
set +C: 关闭上术特性
>|: 在-C特性下,强制使用覆盖重定向
同时重定向标准输出和错误输出:
COMMAND > /path/to/outfile 2> /path/to/errfile
COMMAND &> /path/to/somefile
COMMAND > /path/to/somefile 2> &1
在脚本中重定向:
临时重定向
#!/bin/bash
echo "this is an error" >&2
echo "this is an output."
永久重定向
#!/bin/bash
exec 1>testout
echo "This is test of redrecting all output."
echo "from a script to another file."
把所有的标准输出重定向到文件testout;
#!/bin/bash
exec 2>testerror
yy
重定向所有的标准错误重定向到文件testerror
在脚本中重定向输入
exec 0 从文件testfile中获取输入,而不是从0(标准输入); #!/bin/bash exec 0 count=1 while read line; do echo "Line#$count:$line" let count+=1 done 注:read命令用于读取用户在键盘上的标准输入数据,将stdin重定向到文件后,read会到文件去读取数据,而不是stdin. 创建自定义的重定向 除了0 1 2三个默认的文件描述符(FD)之外,还有3-8几个可以使用的文件描述符 创建输出文件描述符 #!/bin/bash exec 3>test13out echo "this should display on the monitor" echo "this should be stored in the file" >&3 echo "this should display on the monitor" 注:exec将fd 3重定向到文件test13out,所以重定向到&3的文件将被写入test13out
#ifconfig eth0 | grep "inet addr" inet addr:192.168.57.23 Bcast:192.168.57.255 Mask:255.255.255.0 7. 执行算术运算 执行算术运算的四种方式: let varName=算术表达式 varName=$[算术表达式] varName=$((算术表达式)) varName=`expr $num1 + num2` 编写脚本:test.sh #!/bin/bash let varName1=1+1 varName2=$[1+2] varName3=$((1+3)) varName4=`expr 1 + 4` echo "varName1:$varName1" echo "varName2:$varName2" echo "varName3:$varName3" echo "varName4:$varName4" #sh test.sh varName1:2 varName2:3 varName3:4 varName4:5 8. 脚本退出状态码 变量$?用于保存最后一条命令退出的状态码,默认情况下,一个成功结束的命令的退出码为0,也可以在脚本中自定义退出码: exit num(num为保留值之外的数字) num: 0 - 255 0: 命令成功结束 1:通用未知错误 2:误用shell命令 126:命令不可执行 127: 没找到命令 128: 无效退出参数 128+x: Linux信号x的严重错误 130: 命令通过Ctrl + C终止 255: 退出状态码越界 9. 脚本的逻辑控制 if 语句: 单分支: if 条件;then 分支1; fi
双分支: if 条件;then 分支1; else 分支2; fi
多分支: if 条件;then 分支1; elif 条件2;then 分支2; elif 条件3;then 分支3; ... else 分支n; fi 例: if [ ! -d /ccdb ]; then mkdir /ccdb fi for 循环语句: for varName in 列表;do 循环体 done 关于列表读取: 1.直接从列表中读取,比如:for varName in /etc/sysctl.conf /etc/passwd /etc/group 2.从变量中读取,比如:for varName in $varName 3.从命令中读取,比如:for varName in `cat /etc/passwd` 4.从通配符读取目录,比如:for varName in /etc/init.d/*
C语言风格的for格式: for (( variable assignment; condition; iteration process )) 比如: for (( i=1; i<=10; i++)) do echo "The next number is $i" done 例1: for fileName in /etc/{passwd,shadow,group}; do echo $fileName done 例2: for fileName in /etc/*; do echo $fileName done 例3: for fileName in `cat /etc/passwd`; do echo $fileName done 例4: varName=`cat /etc/passwd` for fileName in $varName; do echo $fileName done 例5: for i in {1..10}; do echo $i done while 循环语句: while 条件测试;do 循环体 done 当条件测试为真(测试命令返回的是退出状态码0)时,一直循环,直到退出状态码为非0 例: #!/bin/bash i=0 while [ $i -le 10 ]; do #i小于10时,执行循环;当i大于10时,循环结束。 let i++ echo $i done until 循环语句: until 条件测试;do 循环体;do done 当条件测试退出状态码为非0时执行循环,一旦测试命令退出状态码为0,循环结束 例: #!/bin/bash i=0 while [ $i -ge 10 ]; do #当i小于10时,执行循环;当i大于10时,循环结束。 let i++ echo $i done case语句的语法格式: case用于替代if-then-else的简便形式 case expression in pattern1) suite1 ;; pattern2) suite2 ;; ... patternn) suiten ;; *) other_suite ;; esac 例: #!/bin/bash # myService=`basename $0` lockFile="/var/lock/subsys/$myService" [ $# -lt 1 ] && echo "Usage: $myService {start|stop|restart|status}" && exit 4 case $1 in 'start') touch $lockFile echo "Starting $myService OK" ;; 'stop') rm -f $lockFile echo "Stopping $myService OK" ;; 'restart') rm -f $lockFile touch $lockFile echo "Restarting $myService OK" ;; 'status') if [ -f $lockFile ]; then echo "$myService is running" else echo "$myService is stopped" fi ;; *) echo "Usage: $myService {start|stop|restart|status}" exit 3 ;; esac 10. 条件测试 条件判断的常用类型: 整数测试 字符测试 文件测试 逻辑运算: 与运算:表达式1 && 表达式2 或运算:表达式1 || 表达式2 非运算:! 表达式
bash中如何做测试: test EXPRESSION [ EXPRESSION ] ` EXPRESSION ` 整数测试: 二元测试: num1 OPRAND num2 -gt: 大于 -lt: 小于 -ge: 大于等于 -le: 小于等于 -ne: 不等于 -eq: 等于 例: #/bin/bash sum=0 i=1 while [ $i -le 100 ]; do let sum+=$i let i++ done echo $sum
字符测试: 单目: -n $stringVar: 字符串是否为空,不空为真,空为假; -z $stringVar: 字符串是否为空,空为真,不空为假; 例: #/bin/bash s="hello" if [ -n $s]; then echo "false" fi 双目: !=: 不等于 >: 大于 <: 小于 ==: 等于,等值比较 =~左侧是字符串,右侧是模式,判定左侧的字符串能否被右侧的模式所匹配,通常在[[]]中使用; 例: #!/bin/bash # s="hello world" [[ $s =~ "hello" ]] && echo "success" 文件测试: 单目: -b file: 测试file是否存在且是否是block设备 -c file: 测试file是否存在且是否是字符设备 -d file: 测试file是否存在且是目录 -e file: 测试file是否存在 -f file: 测试文件是否存在且是一个普通文件 -g file: FILE exists and is set-group-ID -G file: FILE exists and is owned by the effective group ID -h file: 测试file是否存在且是一个链接文件和-L功能一样 -L file: -O file: FILE exists and is owned by the effective user ID -p file: 测试file是否存在且是一个管道文件 -r file: 测试file是否存在且有读权限 -s file: 测试file是否存在,文件size大于0 -S file: 测试file是否存在且是一个sock文件 -t file: 测试文件文件描述符是否被一个终端打开 -u file: FILE exists and its set-user-ID bit is set -w file: 测试file是否存在且有写权限 -x file: 测试文件是否存在且有执行权限 例: #!/bin/bash if [ ! -d /backup ]; then mkdir /backup fi
双目: FILE1 -ef FILE2:FILE1 and FILE2 have the same device and inode numbers FILE1 -nt FILE2:FILE1 is newer (modification date) than FILE2 FILE1 -ot FILE2:FILE1 is older than FILE2 例: #!/bin/bash touch /tmp/a.txt ln -s /tmp/a.txt /tmp/b.txt fileName1=/tmp/a.txt fileName2=/tmp/b.txt [ $fileName1 -ef $fileName2 ] && echo "they are the same file." bash编程之组合测试条件深入探讨: 逻辑与:多个条件同时满足 [ CONDITION1 ] && [ CONDITION2 ] [ CONDITION1 -a CONDITION2 ] [[ CONDITION1 && CONDITION2 ]] 注意:前两个使用单或双中括号都可,但,&&不允许用于单中括号中,所以第三种只能用于双中括号中; 逻辑或:多个条件中有一个满足即为真; [ CONDITION1 ] || [ CONDITION2 ] [ CONDITION1 -o CONDITION2 ] [[ CONDITION1 || CONDITION2 ]] 注意:||不允许用于单中括号中; 例:脚本1 #!/bin/bash if [ -d /backup ] && [ -f /backup/test.txt ]; then echo "This file exist!" fi 例:脚本2 #!/bin/bash if [[ -d /backup && -f /backup/test.txt ]]; then echo "This file exist!" fi 脚本1和脚本2的效果完全一样。 if-then的高级特性 使用双尖括号(( expression )) 术语expression可以是任意的数学赋值或比较表达式 双尖括号命令符号: var++: 后增 var--: 后减 ++var: 先增 --var: 先减 !: 逻辑求反 ~: 位求反 **: 求幂 <<: 左位移 >>: 右位移 &: 位布尔和 |: 位布尔或 &&: 逻辑和 ||: 逻辑或 例: #!/bin/bash val1=10 if (( $val1 ** 2 > 90 )); then (( val2 = $val1 ** 2 )) echo "The square of $val1 is $val2" fi 使用双方括号` expression ` 双方括号里的expression使用了test命令中采用的标准字符串进行比较。但它提供了test命令未提供的另一个特性(模式匹配) 例: #!/bin/bash if [[ $USER == r* ]]; then echo "Hello $USER" else echo "Sorry,I do not know you!" fi 11. 处理用户输入 位置参数:$1 $2 ... $n 例:test2.sh #!/bin/bash [ $# -ne 2 ] && echo "Usage: `basename $0` num1 num2" let total=$1 * $2 echo "The first parameter is $1." echo "The second paramter is $2." echo "The total value is $total." echo "This script name is `basename $0` #sh test3.sh 2 5 The first parameter is 2. The second paramter is 5. The total value is 10. This script name is test3.sh. $* 和 $@:用于提取所有位置参数 例: 脚本test4.sh #!/bin/bash count=1 for param in "$*"; do echo "\$* parameter #$count = $param" count=$[$count+1] done count=1 for param in "$@"; do echo "\$@ parameter #$count = $param" count=$[$count+1] done #sh test4.sh apple banana juice pea $* parameter #1 = apple banana juice pea $@ parameter #1 = apple $@ parameter #2 = banana $@ parameter #3 = juice $@ parameter #4 = pea 变量移动: shift: 默认情况下,shift会将每个参数变量减1;变量$3的值会移到$2,变量$2的值会移到$1,而变量$1的值会被删除。 例1: #!/bin/bash sum=0 for i in `seq 1 $#`; do let sum+=$1 shift done echo $sum 例2: #!/bin/bash # [ $# -lt 2 ] && echo "Too less argements, quit" && exit 3 if [[ "$1" == "-u" ]];then userName="$2" shift 2 fi if [ $# -ge 2 ] && [ "$1" == "-v" ]; then verFlag=$2 fi verFlag=${verFlag:-0} if [ -n $verFlag ];then if ! [[ $verFlag =~ [012] ]];then echo "Wrong parameter." echo "Usage: `basename $0` -u UserName -v {1|2}" exit 4 fi fi # echo $userName $verFlag if [ $verFlag -eq 1 ]; then grep "^$userName" /etc/passwd | cut -d: -f1,3,4,6 elif [ $verFlag -eq 2 ];then grep "^$userName" /etc/passwd | cut -d: -f1,3,4,6,7 else grep "^$userName" /etc/passwd | cut -d: -f1,3,4 fi
6. 管道(COMMAND1 | COMMAND2):前一个命令的输出作为后一个命令的输入