为什么学习shell脚本:
自动化管理的重要依据
追踪与管理系统的重要工作
linux的服务启动接口在 /etc/init.d目录下
简单的入侵检测
连续命令单一化
简单的数据处理
跨平台支持与缩短学习历程
编写shell脚本应该注意的问题
注意shell脚本最上面一行需要加上#!/bin/bash用来申明 shell
说明脚本的 内容与功能 版本信息 作者与联系方式 文件创建日期 历史记录
exit n 给系统返回一个执行结果
使用sh命令来执行脚本,也可以改变文件的权限chmod u+x filename.sh
脚本内特殊的命令,使用绝对路径来执行
预先声明与设置脚本运行时需要的环境变量
可以使用var=$((运算内容))来计算 支持 + - * / %
test 参考 linux程序设计chap2
判断符号[]
使用[]需要注意空格的使用
[ "$HOME" == "$MAIL" ] 相当于test $HOME = $MAIL
注意:
中括号内的每个组件都需要用空格来分隔
中括号内的变量,最好用双引号来设置
中括号内的常量,最好用单引号或双引号来设置
比如name=duxing duxing
[ $name == "dx" ]就会报错,相当于[duxing duxing == "dx"]
shell脚本的默认变量($0,$1)
$0 表示执行文件名
$1 表示第一个参数
$2 第二个参数
...
netstat 查看当前主机的网络服务端口(ports)
常见的端口与服务的关系:
80:www
22:ssh
21:ftp
25:mail
获取变量的方式
直接执行式:用户在参数中带上
交互式:利用read读入
函数功能:
function funname(){
代码块
}
函数可以使用参数,和脚本一样使用$1 $2...传递
如:上面的函数可以如下使用 funname arg1 arg2
循环:
while [ 条件 ]
do
代码块
done
until [ 条件 ]
do
代码块
done
for ((初始值; 限制值; 执行步长))
do
代码块
done
可以使用
for var in con1 con2 con3
do
代码块
done
来直接限制循环要执行几次,而且每次$var的内容为 con1 con2 con3 等
通过bash的相关参数来进行判断
sh [-nvx] scripts.sh
选项:
-n 不要执行脚本,仅查询语法问题
-v 在执行脚本前,现将脚本的内容输出到屏幕上
-x 将使用的脚本内容显示到屏幕上
下面的部分来自《linux程序设计 第4版》中的chap2 可以供参考 更多内容会在shell编程的笔记中出现
shell 中使用变量之前不用声明,只是在使用它们的时候创建它们,默认情况下变量以字符串存储
变量名前面需要加上$
如果字符串中间含有空格需要用引号 等号两边不能有空格
可以通过read命令来将用户输入赋值给一个变量
''和\中的变量会以原来的形式被打印,而""中的变量会以变量的值打印
例如
duxing@ubuntu:~/文档/linux$ myvar="hi everyone"
duxing@ubuntu:~/文档/linux$ echo $myvar
hi everyone
duxing@ubuntu:~/文档/linux$ echo '$myvar'
$myvar
duxing@ubuntu:~/文档/linux$ echo "$myvar"
hi everyone
duxing@ubuntu:~/文档/linux$ echo \$myvar
$myvar
duxing@ubuntu:~/文档/linux$ read $myvar
hello world
duxing@ubuntu:~/文档/linux$ echo '$myvar' now equal $myvar
$myvar now equal hi everyone
环境变量
环境变量 说明
$HOME 当前用户的家目录
$PATH 以冒号分隔的用来搜索命令的目录列表
$PS1 命令提示符,通常是$字符,[\u@\h \W]$给出用户名,机器名,当前目录
$PS2 二级提示符,用来提示后续的输入,通常是>字符
$IFS 输入域分隔符,当shell读取输入时,它给出用来分隔单词的一组字符,
$0 shell脚本的名字
$# 传递给脚本的参数个数
$$ shell脚本的进程号,脚本程序通常会用它来生成一个唯一的临时文件
可以通过env命令查看当前环境变量的设置,通过export设置环境变量
通过 echo "$*" 可以打印当前脚本程序的参数 其中* 可以是1,2 如果是* 将打印所有的参数,参数的分隔
靠的是IFS变量的内容 如果设置了了IFS变量可以通过unset IFS来取消设置
which 命令可以查看执行的程序在哪个目录下面
条件命令 test [
基本用法(以判断文件是否存在为例):
if test -f fred.c
then
...
fi
或者:
if [ -f fred.c ]
then
...
fi
注意:
if和then可以放到一行,但是必须在条件后面加上; 如 if [ -f fred.c ];then
必须在[和被检查的条件之间留出空格,test同样
test的用法:
字符串比较 结果
str1 = str2 如果两个字符串相同则返回真 注意等号两边应该有空格,如果没有空格总是为真
str1 != str2 如果两个字符串不相等则返回真
-n str 如果字符串不为空则返回真
-z str 如果字符串为null则返回真
算数比较 结果
exp1 -eq exp2 如果两个表达式相等则返回真
exp1 -ne exp2 如果两个表达式不相等则返回真
exp1 -gt exp2 如果exp1>exp2则返回真
exp1 -ge exp2 如果exp1>=exp2则返回真
exp1 -lt exp2 如果exp1<exp2则返回真
exp1 -le exp2 如果exp1<=exp2则返回真
!exp 如果exp为假则返回真
文件条件测试 结果
类型检测 test -e filename
-d filename 如果文件是一个目录则返回真
-e filename 文件存在则返回真,所以一般使用-f
-b filename 文件是否为一个块设备
-f filename 如果文件是一个普通文件则返回真
-c filename 文件是否为一个字符设备
-S filename 文件是否为一个套接字文件
-p filename 文件是否为管道文件
-L filename 文件是否为链接文件
权限检测 test -r filename
-r filename 如果文件可读则返回真
-w filename 如果文件可写则返回真
-x filename 如果文件可执行则返回真
-u filename 如果文件的set-user-id位被设置则返回真
-g filename 如果文件的set-group-id位被设置则返回真
-k filename 检测文件是否具有Sticky bit 属性
-s filename 文件大小不为0则返回真(文件是否空白)
比较两个文件test file1 -nt file2
-nt 判断file1比file2新
-ot 判断file1比file2旧
-ef 判断file1与file2是否为同一文件(硬链接)
多重判断 test -r filename -a -x filename
-a 两个条件同时成立
-o 两个条件任何一个成立
! 条件取反
注意:
if[ 条件 ] 两边的空格不能省略
exit num 其中num必须>=0
elif 后面也必须跟 then
例如:
1 #!/bin/sh
2
3 echo "Please tell me is it morning? Please answer yes or no"
4
5 read today
6
7 if [ "$today" = "yes" ] #这里的变量today要加上""否则就会在不输入的情况下出错
8 then
9 echo "good morning"
10 elif [ "$today" = "no" ]
11 then
12 echo "good afternoon"
13 else
14 echo "sorry,$today not recognized. enter yes ro no"
15 exit 1
16 fi
17
18 exit 0
echo 命令后面会带一个换行符,如果不想要这个换行符可以使用printf命令 运行在bash的程序可以加-n 选项
for语句
for variable in values
do
statements
done
打印values列表中的字符串
while语句
while condition
do
statements
done
until语句
until condition
do
statements
done
case语句
case variable in
pattern [ | pattern] ...) statements;; #注意这里的|代表的是或的意思,也就是说可以是多个条件
patterh [ | pattern] ...) statements;; #这里的[]不是test的意思,而是可选
...
esac
注意:在使用通配符时要小心,因为即使后面有更加精确的匹配,它也仅匹配第一个,这提示我们需要把最
精确的放到最前面,而把通用化的匹配放到能放的最后面
命令列表
(遵循最短路径求值 short circuit evaluation)
AND列表
statement1 && statement2 && statement3 ... #和C中的and类似,如果第一个为假那么后续语句都不会执行
OR列表
statement1 || statement2 && statement3 ... #同上
语句块
{}
函数
命令:
: 空命令 可以代替true
. scource 引入一个shell脚本文件
eval命令
exec 可以将当前shell替换为一个不同的程序 例如:exec wall "Thanks for
all the fish"
exit n命令 使程序以退出码n退出
expr 命令 求简单数学表达式的值
set 设置参数变量 可以替换原来的参数
shift 参数左移一位
trap 接收到信号采取行动 trap command signal
可以通过trap -l 来查看信号编号及关联的命令
如果要重置某个信号到默认值 那么commamnd填-
如果要忽略某个信号,那么command填''
unset
取消设置的变量或函数
find
格式: find [path] [options] [tests] [actions]
path部分可以使用绝对路径也可以使用相对路径
option
-depth 查看目录本身之前先搜索目录的内容
-follow 跟随符号链接
-maxdepths N 最多搜索N层目录
-mount 不搜索其他文件系统中的目录
tests
-atime N 文件在N天之前被最后访问过
-mtime N 文件在N天之前被修改过
-name pattern 文件名匹配提供的模式
-newer otherfile 文件要比otherfile要新
-type c 文件类型为c 最常见的为d(目录)f(文件)
-user username 文件的拥有者是username
可以使用操作符来测试 -not(!)取反 -and(-a)且 -or(-o)或
actions
直到遇到 \;为止
{}是exec和ok命令的一个特殊类型的参数,他将被当前文件的完整路径替代
-exec command 执行这条命令
-ok command 与-exec类似 但在执行前要用户确认
-print 打印文件名
-ls 对当前文件使用命令ls-dils
grep(general regular expression parser 通用正则表达式解析器)
grep [options] PATTERN [FILES]
options
-c 输出匹配行的数目 而不是输出匹配行
-E 启用扩展正则表达式
-h 取消每个输出行的前缀 即匹配查询模式的文件名
-i 忽略大小写
-l 只列出包含匹配行的文件名 而不输出真正的匹配行
-v 对匹配模式取反 即搜索不匹配的行
命令的执行
xargs见鸟哥linux私房菜chap11.txt
算数扩展$((...))
参数扩展
参数扩展 说明
${param:-default} 如果param为空 不改变它,但返回default
${param:?default} 如果param为空 输出default并终止脚本
${param:+default} 如果param存在且不为空 返回default
${param:=default} 如果param不为空 就返回它的值
否则把它设置成default的值并返回
${#param} 给出param的长度
${param%word} 从param的尾部开始删除与word匹配的最小部分
${param%%word} 最长
${param#word} 头部 最小
${param##word}
here文档(以cat为例)
cat <<特殊标记
文档内容
特殊标记
调试脚本程序
命令行选项 set选项 说明
sh -n set -o noexec 只检查语法错误,不执行命令
set -name
sh -v set -o verbose 在执行命令之前回显他们
set -v
sh -x set -o xtrace 在处理完命令之后回显他们
set -x
sh -u set -o nounset 如果使用了未定义的变量,就报错
set -u
可以通过+o取消设置