0.<
$ wc -l <a>b>c>d>e>EOF5
1.一个shell中的系统环境变量只对该shell和其子shell有效
子shell只能继承父shell的属性, 不能更改父shell的属性
查看shell执行情况可以用sh -x a.sh
2.位置变量和特殊变量
$$: 这个程序的PID
$?: 上次命令的执行结果返回值
$0: 参数情况下表示文件名, 命令下表示当前shell
$1: 第一个参数
$*: 返回一个字符串, 所有参数和空格连接起来 "$1 $2 ..."
$@: 返回多个字符串 "$1" "$2" ...
$#: 返回参数个数
$_: 上一条命令的最后一个参数
3.普通变量导为环境变量(局部变量和全局变量)
全局变量: 对所有shell及其创建的子进程(子shell)可见
局部变量: 只对创建他们的shell可见
export PATH=$PATH:/usr/local/bin #记住赋值、删除和导出的时候没有$符号
4.读取变量
read name #参数-t(表示等待多少秒输入)等
5.查看变量
set命令查看所有已经定义的变量
env命令查看所有环境变量
6.使用变量
变量都是以字符串形式赋值的,默认把变量值当作字符串,declare -i age=22,这里就用 -i 选项把age定义为整型的了。此后每次运算,都把age的右值识别为算术表达式或数字。
age=20age=${age}+1
echo ${age} #输出"20+1"declare-i age=20age=${age}+1
echo ${age} #输出21
单引号不解释变量
双引号解释变量
为与PHP不相混, 最好统一使用 ${varname}, {$varname}在shell中不解释{}
unset var 清除变量
readonly var 变为只读变量
7.数组
#索引数组
arr=(1 2 3)
arr[3]=4#数组赋值
#关联数组
declare-A arr
arr=([name]=John [age]=18)
arr[sex]=male
#数组赋值
newarr=`(echo ${arr[*]})`
newarr=(${arr[@]})
${!array[*]} #取关联数组所有键,单个字符串格式
${!array[@]} #取关联数组所有键,多个字符串格式
${array[*]} #取关联数组所有值,单个字符串格式
${array[@]} #取关联数组所有值,多个字符串格式
${#array[*]} #关联数组的长度
${#array[@]} #关联数组的长度
${arrary[@]:1:2} #切片操作。1表示索引起始位置,2表示切片长度echo ${arr[0]} #注意花括号使用echo ${arr[*]} #打印整个数组for k in ${!arr[@]}; do
echo$kecho${arr[$k]}done
for v in ${arr[@]}; do#遍历数组值echo$vdoneabc() {
newarr=(`echo "$@"`) #重新把参数转为数组
}
a=($@) #把参数转为数组
8.表达式
expr: 对整数型变量进行算术运算 #变量与操作符之间必须以空格分开, 变量用$
expr `expr 2 + 3` / 5
let: 同expr一样为计算功能, 但与expr相反, 不能用空格分开参数, 变量可以不用$, 但为了统一可以用
let c=2+3
let c=a+b
let c=$a+$b
$((...)): $(($a - $b))
$[...]: $[$a - $b]
以上几种都只支持整数运算, 以下语句支持浮点数运算
var=`echo "scale=1;$var*2.0"|bc` #bc(bash calculater)为内置bash计算器, 用内建变量 scale 指定小数点下位数, 默认值为 0(默认输出整数) , 可以在shell直接输入bc命令实战下
var=`echo "$var 1"|awk '{printf("%g",$1+$2)}'`
var=$(awk 'BEGIN{print 7.01*5-4.01 }')
点击查看各个括号与表达式之间区别
9.表达式执行
`cmd`或者$(cmd) #重新开启一个子SHELL去执行
l=`ls /`; echo $l;
10.测试语句(一般不会单独使用, 会配合if, while等使用)
test: 测试范围整数、字符串、文件
整数:
test $a -[ eq|ne|lt|gt|ge|le ] $b;
字符串:
test $a -[ >|=|<= ] $b; #大于号小于号要加转义, 否则表示重定向, "="表示比较而非赋值
test $str1==$str2; test $str1; test -n $str1; test -z $str1; echo $?;
文件:
test -[ d|f|x|r|w|a|s空文件|O属于当前用户|G属于当前用户所属用户组 ] $file
test $file1 -[ nt|ot ] $file2 文件创建时间比较
以上可以用[]进行简化, 两者等同
如: test -d $file 等价于 [ -d $file ] #一定要使用空格
test [ -d $dir -o -f $file ] #-o表示逻辑或 -a表示逻辑与
11.控制语句
if语句, 用来测试命令执行成功与失败(直接使用命令), 或者执行判断数值-字符串-文件(test/[]形式), 或双小括号内表达式形式"(( 1 + 2 < 3))", 或双中括号"[[ $file = "r*" ]]"
可以在多行定义多个语句, 只返回最后一个语句的状态码
1 if [ -d $file ] ; then
2
3 ...4
5 elif ...; then
6
7 ...8
9 else
10
11 ...12
13 fi
如果条件为命令, 则命令执行后$? == 0为真, 否则为假
if ls > aaaa; then
echo 'aaaa'
else
echo 'bbbb'
fi#输出aaaa
for语句
1 #for 变量名 in名字列表/路径匹配/数组/{1..10}2 #do
3 # ...4 #done
5
6 for day inmon tue wed thu fri sat sun7 do
8 echo$day9 done
case语句
1 #case 变量 in
2 # 字符串1)3 # ...4 # ;;5 # 字符串n)6 # ...7 # ;;8 # esac
9
10 case $op in
11 a|b|c)12 echo 'c';;13 d)14 echo 'd';;15 *)16 echo '*'17 esac
while语句
1 #while条件2 #do
3 # 命令4 #done
5
6 while [ -d /etc ]7 do
8 ls -ld /etc9 done
10
11 num=1
12 while [ $num -le 10]13 do
14 sum=`expr $num *$num`15 echo $sum
16 num=`expr $num + 1`17 done
until语句
1 #until条件2 #do
3 # 命令4 #done
5
6 until [ -x /etc/inittab ]7 do
8 /bin/ls -l /etc/inittab9 exit 0
10 done
11
12 read input13 until [ "$input" == "Y" ] || [ "$input" == "y"]14 do
15 echo "Error"
16 read input17 done
break, continue跳出循环
shift指令: 参数左移, 每执行一次, 参数序列顺序依次左移一个位置, $#的值减1; 用于分别处理每个参数, 移出去的参数不可再用;
1 if [ $# -le 0 ]; then
2 echo 'Not enough parameters'
3 exit 0
4 fi
5
6 sum=0
7 while [ $# -gt 0]8 do
9 sum=`expr $sum + $1`10 shift
11 done
12 echo $sum
函数的定义
1 #函数名() {2 # 命令3 #}4
5 #函数的调用不带()6 #函数名 参数1 参数27
8 #函数中的变量9 #变量均为全局, 没有局部变量10
11 help() {12 echo 'abcd'
13 }14
15 调用: help
函数的返回值
1.默认返回值是最后一条语句返回的状态码
2.return语句, 但是返回值必须在0~255之间, 用$?检查后是返回值
3.使用输出(比如echo语句)作为返回值
作用域
默认情况下, 你在脚本中定义的任何变量都是全局变量, 在函数外定义的变量可以在函数内部正常访问
abc() {
a=10}
abcecho $a #会输出10
local关键字把变量限制在函数内, 即局部变量
递归
factorial() {if [ $1 -eq 1 ]; then
echo 1
elselocal temp=$[ $1 - 1]
local result=`factorial $temp`echo $[ $result * $1]fi}
使用库文件
一个文件定义了各种函数, 怎么导入?直接执行?会创建一个新的shell并在新的shell中运行此脚本, 为新的shell定义几个变量或者函数, 不会用到本shell
解决: 使用 source命令, 或者别名 "."
使用 select in 创建菜单
#option的值是字符串, 而非选择的整数值select option in "Display Errors" "Display Warnings" "Display Notice"
do
case $option in
"Display Errors")echo "Errors";;"Display Warnings")echo "Warnings";;"Display Notice")echo "Notice";;*)echo "Wrong";;esac
done
菜单也可以使用dialog库来创建
a=$'
' #单引号
for时如果每次都有输出, 可以在done之后添加重定向
利用read读取文件
count=1
cat test |whileread linedo
echo "Line ${count}: ${line}"count=$[ $count + 1]done
echo "Finished processing the file"
重定向到其他文件描述符, 使用 >&1、>&2
echo 'aaaaa' >&2
永久重定向
exec 0
exec1>testlog
看例子
exec 0
count=1
whileread linedo
echo "Line ${count}: ${line}"count=$[ $count + 1]done
echo "Finished processing the file"
从永久重定向的文件描述符中恢复, 创建文件描述符
exec 3>&1
echo 'aaaa' >&3exec1>testinfo
exec1>&3
先将STDIN文件描述符保存到另外一个文件描述符, 读取完文件之后再将STDIN恢复到它原来的位置
exec 6
count=1
whileread linedo
echo "Line #$count: $line"count=$[ $count + 1]doneexec0
关闭文件描述符
exec 3>&-
查看文件描述符列表
lsof -p $$
bash4179 root 0u CHR 136,1 0t0 4 /dev/pts/1bash4179 root 1u CHR 136,1 0t0 4 /dev/pts/1bash4179 root 2u CHR 136,1 0t0 4 /dev/pts/1bash4179 root 255u CHR 136,1 0t0 4 /dev/pts/1#因为STDIN, STDOUT, STDERR都指向终端, 所以文件名为终端设备名
快速删除和创建文件(清空文件内容)
cat /dev/null > filename
mktemp在/tmp创建临时文件, 如果要指定文件名, 需要在文件名后加6个X, 从而保证文件名在此文件夹中是唯一的
mktemp
mktemptest.XXXXXX #tmp.z8mAKOmktemp -d test.XXXXXX #创建临时文件夹mktemp -t test.XXXXXX #强制在系统的/tmp文件夹内创建临时文件
tee 将输出一边发送到标准输出一边发送到文件, 默认是覆盖文件, 追加使用 -a 选项
who |teefname
root pts/1 2015-09-22 09:22 (xx.xx.xx.xx)
信号: 用于进程间通讯
strap捕捉信号 strap "处理信号命令行" 信号列表
#!/bin/bash
#程序执行完退出时的信号为EXIT
trap"count=10"SIGINT SIGTERM
#trap"echo 'Sorry! I have trapped the Ctrl-C'"
echoThis is a test program
count=1
while [ $count -le 10]do
echo "Loop #$count"
sleep 5count=$[ $count + 1]donetrap-SIGINT #移除信号echo This is the end of the test program
nice, renice用来修改优先级, -20 <= 优先级 <= 20, 越小优先级越高(好人难做)
at可以指定某个时间执行某执行令, 该指令会被提交到作业队列中, 作业队列会保存通过at命令提交的待处理的作业, at的守护进程atd会以后台模式运行, 并检查作业队列来运行作业; 但是作业在Linux系统上运行时, 没有屏幕会关联到改作业, Linux会将提交该作业用户的E-mail地址作为STDOUT, STDERR, 任何发送到STDOUT, STDERR的输出都会通过邮件发送给该用户
atq列出等待的作业
atrm 作业号 删除作业
at.sh
#!/bin/bashecho This script ran at `date`echo This is the end of the scripit >&2
定时执行
at -f at.sh 10:39
HH:MM 在今日的 HH:MM 时刻进行, 若该时刻已超过, 则明天的 HH:MM 进行此任务
HH:MM YYYY-MM-DD 强制规定在某年某月的某一天的特殊时刻进行该项任务
HH:MM[am|pm] [Month] [Date] 强制在某年某月某日的某时刻进行该项任务
HH:MM[am|pm] + number [minutes|hours|days|weeks] 在某个时间点再加几个时间后才进行该项任务
完