命令解析器——例如bash
是一个程序,可以解析shell命令
shell基本语法
变量
环境变量
敲命令“env”可以取出所有环境变量
环境变量可以当全局变量来使用
set命令可以输出当前系统的全部环境变量以及函数
unset命令用于删除一个环境变量
本地变量
自定义的变量——局限在某个脚本中使用
1、变量定义:
shell中的变量没有数据类型 - 默认值都是string类型VAR=hello or VAR=“hello”
注意事项:
定义shell变量的时候,建议变量名大写
赋值的时候=前后不能有空格
2、一些命令实例
将一个命令执行之后的结果赋值给某个变量(下面两种方式都可以)
var=`pwd`
var=$(pwd)
算术运算(只能在整型之间做算数运算)
var=9
var=$((var 10))
var=$[var 10]
用export命令可以把本地变量导出为环境变量
export VARNAME //只在当前终端中有效
export VARNAME=value
位置变量
$0 - 相当于C语言main函数的argv[0]
$1、$2...相当于C语言main函数的argv[1]、argv[2]...
特殊变量
$#: 这个程序的参数个数
$*: 表示参数列表"$1" "$2" ...
$@: 表示参数列表"$1" "$2" ...
$$: 这个程序的PID
$?: 执行上一个命令的返回值
注意!!!加上“”之后,$*和$@会发生变化!!!
for循环时候"$*" 将所有的参数作为一个整体
for循环时候"$@"有多少个参数被拆分成几部分
命令代换
将执行完命令之后得到的数据保存到变量
VAR=`shell命令`
VAR=$(shell命令) -- 常用,推荐使用
算术代换
1、对变量取值
在变量的前边加 $
$VAR
2、对变量做算术运算
算术运算: -*/
算术运算操作的必须是整数
VAR=$(($VAR*10))
VAR=$[$VAR-10]
3、进制运算
$[base#n] 数值按照几进制进行运算
base - 进制
#连接符
n:数值
转义字符
\
将有特殊意义的字符变成普通字符
将普通字符变成有特殊意义的字符 - 正则表达式中使用
单引号
VAR='$(date)'
单引号中的内容原样输出
双引号
VAR="$(date)"
会继续双引号中的命令, 输出结果字符串
条件测试
条件测试命令
下面两种方式皆可
test
[ ]
比较test , [] , [[]]
test 和[是 bash 的内部命令
[[是 bash 程序语言的关键字!
绝大多数情况下,这个三个功能通用。但是命令和关键字总是有区别的。
区别:
在[[中使用&& 和||
[ 中使用-a和 -o表示逻辑与和逻辑或
如何判断条件是否成立?
如果返回值为0: 成立
返回值为非0: 不成立
例子:
上图中pwd执行成功了,因此返回值是0
文件状态测试
linux中的文件种类: 7种
普通文件: f
目录: d
符号链接:l
套接字:s
管道:p
字符设备:c
块设备:b
-b filename
当filename 存在并且是块文件时返回真(返回0)
-c filename
当filename 存在并且是字符文件时返回真
-d pathname
当pathname 存在并且是一个目录时返回真
-e pathname
当由pathname 指定的文件或目录存在时返回真
-f filename
当filename 存在并且是正规(普通)文件时返回真
-g pathname
当由pathname 指定的文件或目录存在并且设置了SGID 位时返回真
-h/-L filename
当filename 存在并且是符号链接文件时返回真 (或 filename)
-k pathname
当由pathname 指定的文件或目录存在并且设置了"粘滞"位时返回真
-p filename
当filename 存在并且是命名管道时返回真
-r pathname
当由pathname 指定的文件或目录存在并且可读时返回真
-s filename
当filename 存在并且文件大小大于0 时返回真
-S filename
当filename 存在并且是socket 时返回真
-t fd
当fd 是与终端设备相关联的文件描述符时返回真
-u pathname
当由pathname 指定的文件或目录存在并且设置了SUID 位时返回真
-w pathname
当由pathname 指定的文件或目录存在并且可写时返回真
-x pathname
当由pathname 指定的文件或目录存在并且可执行时返回真
-O pathname
当由pathname 存在并且被当前进程的有效用户id 的用户拥有时返回真(字母O 大写)
-G pathname
当由pathname 存在并且属于当前进程的有效用户id 的用户的用户组时返回真
file1 -nt file2
file1 比file2 新时返回真
file1 -ot file2
file1 比file2 旧时返回真
f1 -ef f2
files f1 and f2 are hard links to the same file
例如,测试文件filename是否为目录文件
常见字符串测试
-z string
字符串string 为空串(长度为0)时返回真
-n string
字符串string 为非空串时返回真
str1 = str2
字符串str1 和字符串str2 相等时返回真
str1 == str2
同 =
str1 != str2
字符串str1 和字符串str2 不相等时返回真
常见的数值测试
==——eq —— equal
!=——ne—— not equal
>——gt —— greater than
>=——ge——greater than equal
<=—— le—— less than equal
nt1 -eq int2
如果int1 等于int2,则返回真
int1 -ne int2
如果int1 不等于int2,则返回真
int1 -lt int2
如果int1 小于int2,则返回真
int1 -le int2
如果int1 小于等于int2,则返回真
int1 -gt int2
如果int1 大于int2,则返回真
int1 -ge int2
如果int1 大于等于int2,则返回真
测试时使用的逻辑操作符
a - && : and
o - ||: or
取反:!-a
逻辑与,操作符两边均为真,结果为真,否则为假。
-o
逻辑或,操作符两边一边为真,结果为真,否则为假。
!
逻辑否,条件为假,结果为真。
shell脚本语法 - 分支
if/then/elif/else/fi
语法格式
if [ 条件判断语句 ];then
处理语句
处理语句
elif [ 条件判断语句 ]
then
处理语句
处理语句
else
处理语句
处理语句
fi
:——是一个特殊的命令,称为空命令
该命令不做任何事,但Exit Status总是真。
if :; then
xxxx
fi
case/esac
基本语法
case 变量 in
yes|Yes|y|Y)
处理语句
处理语句
;;
No|no|n|N)
处理语句
处理语句
;;
*)
处理语句
;;
esac
*类似于default
case类似于switch
::类似于break
例子
a.sh
./a.sh aa
VAR=$1
case VAR in
a*|AA|a|A)
echo "a"
;;
b|bb|BB)
echo b
;;
*)
echo "hello"
;;
esac
shell脚本语法 - 循环
for/do/done
语法格式
for 变量 in list(列表);do
控制语句
控制语句
done
例子(下面两个for循环的结果相同)
for VAR in $(ls) ;do
echo $VAR
done
for VAR in `ls` ;do
echo $VAR
done
while/do/done
语法格式
while [ 条件测试语句 ];do
控制语句
控制语句
done
例子——输入三次密码,三次错误退出程序
PWD=world
count=1
echo "请输入密码"
read TMP
while [ $TMP != $pwd -a $count le 3 ];do
echo "密码错误,请重新输入"
read TMP
count=$[count 1]
do
break和continue
break 可以选择跳出的层数
break n
输入和输出
echo
echo 字符串
-e: 解析字符串中的\n字符
-n:去掉echo默认加上的换行符
例子:
文件重定向
cmd > file
file - 文件名
cmd >> file
内容追加到file文件中
例子——将指令cmd的标准输出(1)重定向到file,标准错误(2)重定向到标准输出(1)——标准输出和标准错误都写入file文件中
cmd > file 2>&1
#等价于
cmd 1 > file 2 > &1
1前面加&代表1是文件描述符,不加&,则1代表一个文件
awk
处理行和列,主要用于列的处理
1、awk缺省的行分隔符是换行
2、缺省的列分隔符是连续的空格和Tab
3、如何取出每一列
$0: 当前行,还没有拆分
$1: 第一列
$2: 第二列
。。。。。
4、如果不是缺省分隔符的如何指定分隔符
-F后边跟的就是指定的分隔符
5、例子——拆分/etc/passwd,找到每个用户对应的家目录
awk -F: '{print $6}' /etc/passwd
一般格式
awk 参数 '/pattern/{actions}' 目标文件
awk 参数 'condition{actions}' 目标文件
awk 参数 脚本文件 目标文件
condition -- 条件
pattern -- 正则表达式
actions -- 匹配成功后的一系列操作
例子——找出以g开头的字符串的第三列
awk -F/ '/^g/{print $3}' test
如何定义变量
需要变量直接写即可,默认值0
定义变量的时候直接指定一个初始值——利用“-v”设定初始值awk -v x=10 '条件/正则表达式{action} ' 文件名
练习:从ps aux得到的数据中找出pid>1000 && pid <2000的进程的个数
第一步——找出所有进程号在1000到2000之间的进程
ps -aux | awk '$2>1000 && $2<2000{print $2}'
第二步,设置变量x(x的默认值为0),用于记录当前符合条件的进程号是第几个符合条件的
ps -aux | awk '$2>1000 && $2<2000{print $2; x=x 1; print x}'
第三步,添加条件END(END——代表遍历结束)
ps -aux | awk '$2>1000 && $2<2000{x=x 1}END{print x}'
shell脚本例子一
#!/bin/bash
# 关闭tracker 和 storage服务
#shell脚本没有返回值,没有参数,但是可以传参
tracker_start()
{
#查找名为fdfs_trackerd的进程; grep -v grep的意思是过滤掉grep进程
#> /dev/null重定向到垃圾回收站,扔进去之后,输出就没有了
ps aux | grep fdfs_trackerd | grep -v grep > /dev/null
#如果查到了该进程,则$?的值是0
if [ $? -eq 0 ];then
echo "fdfs_trackerd 已经在运行中, 无需启动..."
else
#说明该进程没有被启动
sudo fdfs_trackerd /etc/fdfs/tracker.conf
if [ $? -ne 0 ];then
echo "tracker start failed ..."
else
echo "tracker start success ..."
fi
fi
}
storage_start()
{
ps aux | grep fdfs_storaged | grep -v grep > /dev/null
if [ $? -eq 0 ];then
echo "fdfs_storaged 已经在运行中, 无需启动..."
else
sudo fdfs_storaged /etc/fdfs/storage.conf
if [ $? -ne 0 ];then
echo "storage start failed ..."
else
echo "storage start success ..."
fi
fi
}
#如果没传入参数
if [ $# -eq 0 ];then
echo "Operation:"
echo " start storage please input argument: storage"
echo " start tracker please input argument: tracker"
echo " start storage && tracker please input argument: all"
echo " stop storage && tracker input argument: stop"
exit 0
fi
case $1 in
storage)
storage_start
;;
tracker)
#调用shell函数tracker_start
tracker_start
;;
all)
storage_start
tracker_start
;;
stop)
sudo fdfs_trackerd /etc/fdfs/tracker.conf stop
sudo fdfs_storaged /etc/fdfs/storage.conf stop
;;
*)
echo "nothing ......"
esac
get技能
1、grep -v grep ——过滤掉grep
2、> /dev/null——将输出扔掉
shell脚本例子二
#!/bin/bash
#定义变量
START=1
STOP=1
case $1 in
start)
START=1
STOP=0
;;
stop)
START=0
STOP=1
;;
"")
STOP=1
START=1
;;
*)
STOP=0
START=0
;;
esac
# **************************** 杀死正在运行的CGI进程 ****************************
if [ "$STOP" -eq 1 ];then
# 登录
kill -9 $(ps aux | grep "./bin_cgi/login" | grep -v grep | awk '{print $2}') > /dev/null 2>&1
echo "CGI 程序已经成功关闭, bye-bye ..."
fi
# ******************************* 重新启动CGI进程 *******************************
if [ "$START" -eq 1 ];then
# 登录 -n代表不加换行
echo -n "登录:"
spawn-fcgi -a 127.0.0.1 -p 10000 -f ./bin_cgi/login
echo "CGI 程序已经成功启动 ^_^..."
fi
get技能
1、> /dev/null 2>&1——将标准输出和标准错误全都扔掉
2、 echo-n——不加换行
shell脚本例子三
#!/bin/bash
NAME=redis
FILE=redis.pid
# 判断redis目录是否存在, 如果不存在则创建
is_directory()
{
#如果传入的第一个参数不是目录
if [ ! -d $1 ]; then
echo "$1 目录创建中..."
mkdir $1
if [ $? -ne 0 ];then
echo "$1 目录创建失败, ~~~~(>_
exit 1
fi
fi
}
# 判断redis目录是否存在, 如果不存在则创建
is_regfile()
{
if [ ! -f $1 ]; then
#statements
echo "$1 file not exist..."
return 1
fi
return 0
}
# 根据参数设置redis状态
#提示用户需要传入参数
if [[ $1 = "" ]];then
echo "please input argument:"
echo " start: start redis server"
echo " stop: stop redis server"
echo " status: show the redis server status"
exit 1
fi
# 函数调用,函数传入的参数是$NAME
is_directory $NAME
case $1 in
start)
# 判断 redis-server 进程是否已经启动...
ps aux | grep "redis-server" | grep -v grep > /dev/null
if [ $? -eq 0 ];then
echo "Redis server is runing ..."
else
# 删除$FILE 文件
unlink "$NAME/$FILE"
echo "Redis starting ..."
redis-server ./conf/redis.conf
if [ $? -eq 0 ];then
echo "Redis server start success!!!"
# 休眠1s, 等待pid文件被创建出来, 再进行后续判断
sleep 1
if is_regfile "$NAME/$FILE";then
# printf是一个命令,用于在中断进行输出
printf "****** Redis server PID: [ %s ] ******\n" $(cat "$NAME/$FILE")
printf "****** Redis server PORT: [ %s ] ******\n" $(awk '/^port /{print $2}' "./conf/redis.conf")
fi
fi
fi
;;
stop)
# 判断 redis-server 进程是否已经启动...
ps aux | grep "redis-server" | grep -v grep > /dev/null
if [ $? -ne 0 ];then
echo "Redis server is not runing..."
exit 1
fi
echo "Redis stopping ..."
# 判断pid文件是否存在
#调用函数is_regfile,传入的参数罗列在函数调用的后面,即$NAME/$FILE
if is_regfile "$NAME/$FILE"; then
# 读进程文件
echo "### 通过 redis.pid文件 方式关闭进程 ###"
PID=$(cat "$NAME/$FILE")
else
# 查找进程ID
echo "### 通过 查找进程ID 方式关闭进程 ###"
PID=$(ps aux | grep "redis-server" | grep -v grep | awk '{print $2}')
fi
echo Redis server pid = $PID
kill -9 $PID
if [ $? -ne 0 ]; then
echo "Redis server stop fail ..."
else
echo "Redis server stop success!!!"
fi
;;
status)
ps aux | grep "redis-server" | grep -v grep > /dev/null
if [ $? -eq 0 ];then
echo "Redis server is running..."
else
echo "Redis server is not running ..."
fi
;;
*)
echo "do nothing ..."
;;
esac
来源:http://www.icode9.com/content-3-123051.html