先写一个Shell脚本文件
1 #!/bin/bash #脚本默认开头
2
3 echo "hello!"
默认没有执行权限x,可通过chmod添加
$ sudo chmod +x T01.sh #添加执行权限
$ bash T01.sh #通过bash执行脚本
$ ./T01.sh #直接执行脚本

$ myname="hello I am xiaona!" #普通变量赋值
$ echo $myname #引用普通变量
$ env #查看系统环境变量
$ export PATH=dir/ #修改PATH的变量为dir/
$ export PATH=$PATH:dir/ #PATH再增加一个目录(增加新的值需要使用:分隔开,不该便原有的值)
$ source ~/.bashrc #使刚添加的环境变量生效
# 命令行变量
$ ./T01.sh abcd 1234 #以这行命令为例子
# $0 保存的当前脚本名字(文件名字)
# $# 代表命令行的参数个数,即2
# $* 代表所有的参数,即abcd、1234
# $@ 代表所有的参数,即abcd、1234
# $n 代表第n个参数,如$1表示abcd,$2表示1234
# 两个特殊变量 $?和$$
# $? 代表最后一个命令的返回值
# $$ 代表当前Shell的进程号PID
# $! 后台运行的最后一个进程的PID号
# $- 使用set及其执行时传递给Shell的标志位
单引号:单引号内不允许任何变量、元字符、通配符、转义符被shell解析,均被原样输出。
双引号:保护特殊元字符和通配符不被shell解析,但是允许变量和命令的解析,以及转义符的解析。
反引号:反引号的功能是命令替换,在反引号(``) 中的内容通常是命令行,程序会优先执行反引号中 的内容,并使用运行结果替换掉反引号处的内容。

$ ls notexist 2> a.txt #(notexist是一个不存在的文件,所以将错误信息重定向到a.txt中)
$ echo 0< a.txt #echo读取a.txt的内容
$ echo "hello world" 1>&2 #重定向到标准错误设备
# 在脚本中,在重定向的右边,标准输入、标准设备文件描述符要写成&0、&1和&2
字符串的处理
$ echo "${#var}" #计算var变量的字符数
$ echo "${var#apple}" #删除var变量的左边字符串apple
$ lev=${var%%[a-zA-Z]*} #删除var变量的右边字符串
# 从右到左 %%贪恋匹配(尽可能多的匹配) %无贪恋原则(尽可能少的匹配)
# 从左到右 ##贪恋匹配 #无贪恋原则

| 语法 | 功能 |
|---|---|
| 变量=${参数:-word} | 如果设置了参数,则用参数的值置换变量的值,否则用word置换 |
| 变量=${参数:=word} | 如果设置了参数,则用参数的值置换变量的值,否则word赋给参数,然后word替换给变量 |
| 变量=${参数:?word} | 如果设置了参数,则用参数的值置换变量的值,否则就显示word并Shell退出 |
| 变量=${参数:+word} | 如果设置了参数,则用参数的值置换变量的值,否则不进行置换 |
# 单分支语句
if [ -e file ] && [ -r file ] then #file文件是否存在,是否可读
cat file #查看该文件
fi
## if-else的多分支写法
if [ -e file ] && [ -r file ] then #方括号内的左右两边都要空格隔开
cat file
elif [ -e file ] then
chmod u+r file #授予读权限
cat file
else #只有else不需要then,其他的if-else的分支都需要then
touch file
fi
## case分支的写法
read VAR #从键盘接收一个用户输入,付给变量VAR
case $VAR in #判断VAR变量的值
1) echo "one";; #若值为1,则输出one
2) echo "two";; #每个分支都必须以双分号作为结束(最后一个分支除外)
*) echo "unknown" #星号*匹配任意字符
esac #必须以esac结尾,1可以是'1'
##while的循环
declare -i n=0 #declare -i 表示该变量为数值
while [ $n -le 100 ] #条件n小于等于100循环
do #循环提用do和done包含起来
echo "$n"
n=$n+1 #变量n的自加1
done
##until的循环
declare -i n=0 #declare -i 表示该变量为数值
until [ $n -gt 100 ] #条件n小于等于100循环 until是条件不成立执行循环体
do #循环提用do和done包含起来
echo "$n"
n=$n+1 #变量n的自加1
done
##for的循环
files=`ls` #当前目录下的文件名放在变量files中 每个值以空格分开
for i in $files #遍历files
do
if [ -f $i ] then #若是普通文件
wc -l $i #计算$i 该文件的行数
fi
done
#或者for的另一种写法
##for的循环
for((i=1;i<=10;i++)) #双括号的for循环
do
sum=$(expr $sum + $i) #expr支持算术运算
echo $sum #求和输出sum
done
##定义函数和函数调用
check_user() #定义函数 ()中无空格
{
if [ $1 = "quit" ] then #若位置参数第一个为quit,则立即退出
exit # $0表示文件名,位置参数0,exit表示退出命令
fi
USER=`who | grep $1 | wc -l`
if [ $USER -eq 0 ] then
return 0 #return 该函数结束
else
return 1 #用户在先返回1,不在线返回0
fi
}
while true #死循环
do
echo -n "input a user name:" # echo -n 表示不换行
read USER #接收键盘输入
#上面的的等效写法
# read -p "input a user name:" USER
check_user $USER #函数调用 并传递参数$USER
if [ $? -eq 1 ] then # $?是上一步命令执行的结果接收变量;这里值函数调用后传来的参数值
echo "[$USER] online."
else
echo "[$USER] offline."
fi
done
#### trap的使用
$ trap "" INT #当脚本收到信号SIGINT时,忽略该信号
$ trap do_something INT QUIT HUP #当脚本收到信号INT、QUIT或HUP时执行函数do_something
$ trap on_exit EXIT #当脚本正常退出时,执行on_exit函数
#当脚本正常退出时执行函数on_exit,当脚本文件收到某个信号INT或HUP时执行空指令
#此时冒号代表一个空指令,如果没有冒号,脚本将完全忽略该信号,不做响应,不能立即退出
#执行顺序时由下而上,即先执行冒号空语句,再执行EXIT的执行函数on_exit函数
$ trap on_exit EXIT
$ trap ":" INT HUP
$ trap -l #产看系统默认支持的信号类型前缀SIG可以忽略