Shell 脚本
Shell 脚本
语法
概述
shell是命令解析器,接收应用程序命令,调用系统内核
sh默认是bash,乌班图中默认是dash,还其他有csh,zsh等
bash前身是Bourne shell,后发展为Bourne- again shell,即bash
脚本
创建:touch、vim
编辑:
- 以#!/bin/bash 开头(指定解析器)
- 一行多个命令用;隔开
执行
方式一:sh 脚本路径、bash 脚本路径
方式二:
赋予执行权限 chmod u+x 脚本 --->
路径执行,注意,相对路径不能省略./
chmod u+x helloworld.sh ./helloworld.sh
方式三:. 路径、source 路径
. text
**说明:**前两种都是shell中打开了子shell,而最后一种在本shell中解析,区别就在于,环境变量的继承关系,如在子 shell 中设置的 当前变量,父 shell 是不可见的。
变量
系统预定义变量 $大写字母
set 显示所有变量
自定义变量 变量名=变量值
unset 变量名 撤销变量
export 变量名 升为全局变量,在子shell也可以调用
s=5 vim test.sh =============================== #!/bin/bash echo $s =============================== sh test.sh #无输出,这种执行方式开了子shell,s不是全局变量 =============================== export s sh test.sh 5静态变量(常量) readonly 变量名,静态变量不能撤销
=前后不能有空格
默认类型都是字符串,不能运算
s=5 echo $s+$s #5+5变量值有空格,加引号
特殊变量
$1-$9 ,${10} ... 第几个参数 $0代表脚本名称$# 参数个数
$* 所有参数
$@ 所有参数
$* = $@ = "$@""$*" 把所有参数作为一个字符串
for i in "$@" do echo $i真漂亮 done sh test.sh 刘思思 李某某 #刘思思真漂亮 #李某某真漂亮 =========================== #换成“$*” #刘思思 李某某真漂亮
$? 返回值(反人类)
- 正常执行返回0,不正常执行返回1-255
- 接收返回值0-255 *
运算符
$(())、$[]
条件判断
test [ 条件 ]
- 前后必须有空格
- 非空为true
- 比较 -eq、-ne、-lt、-le、-gt、-ge
- 权限 -r、-w、-x
- 文件类型 -e 文件存在、-f 是文件、-d 是目录
类似三元运算
- [ 条件 ] && 命令1 || 命令2
流程控制
if [ 条件 ] ;then 命令 ;fi
if [ 1=1 ];then echo ok; fi =============================== if [ 1=1 ] then echo ok fiif [ 条件 ] ;then 命令 ;elif [ 条件 ] ;then 命令; else 命令; fi
case $变量名 in "值1") 命令;;"值2") 命令;;esac
case $s in "1")echo 我是1 ;; "2") echo 我是2;;esac =============================== case $s in "1") echo 我是1 ;; "2") echo 我是2;; esacfor ((初始值;循环条件;迭代)) ;do 命令 ;done
for((i=0;i<=100;i++));do sum=$[$sum+$i]; done;echo $sum =============================== for((i=0;i<=100;i++)) do sum=$[$sum+$i] done echo $sumfor 变量 in 值1 值2 值3 ;do 命令;done
for i in 1 2 3 4 5;do sum=$[$sum+$i];done;echo $sum =============================== for i in 1 2 3 4 5 do sum=$[$sum+$i] done echo $sumwhile [ 条件 ] ;do 命令;done
i=0;while [ $i -le 100 ];do sum=$[$sum+$i] i=$[$i+1];done;echo $sum =============================== while [ $i -le 100 ] do sum=$[$sum+$i] i=$[$i+1] done echo $sum =============================== i=0;while (($i <= 100));do sum=$[$sum+$i] i=$[$i+1];done;echo $sum
读控制台
read -p "提示" -t 等待时间 变量名
read -p "请在3s内输入姓名:" -t 3 name echo $name,欢迎你!
函数
basename 路径 [后缀] 在路径中提取文件名 ,本质上就是把路径最后部分剪切下来,不会进行路径校验
- .后缀 把后缀也去掉
dirname 绝对路径 去除文件名 ,返回剩下的路径
自定义函数
[function] 函数名(){
命令
return int
}
- 必须先生命函数才能调用
- 函数返回值,只能通过$?系统变量获得,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。return 后跟数值 n(0-255)
sum(){ s=0 s=$[$1+$2] echo $s } read -p"请输入参数1:" x read -p"请输入参数2:" y sum $x $y
正则表达式
使用全的功能需要加 -E
使用转义字符时加单引号
cat /etc/passwd | grep r[a,b,c]*t cat /etc/passwd | grep ‘a\$b’
文本处理
grep 取行
cut [] 文件名 取列
- -f 列号
- -d 分隔符,默认是“\t”制表符
- -c 2 按字符切,取第2列
- 支持,-
ifconfig ens33 | grep netmask | cut -d " " -f 10 192.168.111.101awk [] '/匹配命令/{执行命令} /匹配命令/{执行命令} ...' 文件名
- F 分隔符
- -v 赋值一个用户定义变量
- {print
$1","$7} 输出第一列,第七列 - BEGIN{print "user, shell"} 在输出的最前面加user, shell
- END{print "dahaige,/bin/zuishuai"} 在输出的最后面加dahaige,/bin/zuishua
- 内置变量
- FILENAME 文件名
- NR 行号
- NF 列数
#只显示/etc/passwd 的第一列和第七列,以分号分割,且在所有行前面添加列名usershell在最后一加"dahaige,/bin/zuishuai"。 awk -F : 'BEGIN{print "user, shell"} {print $1","$7} END{print "dahaige,/bin/zuishuai"}' passwd #将 passwd 文件中的用户 id 增加数值 1 并输出 awk -v i=1 -F : '{print $3+i}' passwd #统计 passwd 文件名,每行的行号,每行的列数 awk -F : '{print "filename:" FILENAME ",linenum:" NR ",col:"NF}' passwd
案例
归档文件
实际生产应用中,往往需要对重要数据进行归档备份。 需求:实现一个每天对指定目录归档备份的脚本,输入一个目录名称(末尾不带/), 将目录下所有文件按天归档保存,并将归档日期附加在归档文件名上,放在/root/archive 下。 这里用到了归档命令:tar 后 面 可 以 加 上 -c 选 项 表 示 归 档 , 加 上 -z 选 项 表 示 同 时 进 行 压 缩 , 得 到 的 文 件 后 缀 名 为.tar.gz。
#!/bin/bash
# 首先判断输入参数个数是否为 1
if [ $# -ne 1 ]
then
echo "参数个数错误!应该输入一个参数,作为归档目录名"
exit
fi
# 从参数中获取目录名称
if [ -d $1 ]
then
echo
else
echo
echo "目录不存在!"
echo
exit
fi
DIR_NAME=$(basename $1)
DIR_PATH=$(cd $(dirname $1); pwd)
# 获取当前日期
DATE=$(date +%y%m%d)
# 定义生成的归档文件名称
FILE=archive_${DIR_NAME}_$DATE.tar.gz
DEST=/root/archive/$FILE
# 开始归档目录文件
echo "开始归档..."
echo
tar -czf $DEST $DIR_PATH/$DIR_NAME
if [ $? -eq 0 ]
then
echo
echo "归档成功!"
echo "归档文件为:$DEST"
echo
else
echo "归档出现问题!"
echo
fi
exit
发送消息
我们可以利用 Linux 自带的 mesg 和 write 工具,向其它用户发送消息。 需求:实现一个向某个用户快速发送消息的脚本,输入用户名作为第一个参数,后面直接跟要发送的消息。脚本需要检测用户是否登录在系统中、是否打开消息功能,以及当前发送消息是否为空。
#!/bin/bash
login_user=$(who | grep -i -m 1 $1 | awk '{print $1}')
if [ -z $login_user ]
then
echo "$1 不在线!"
echo "脚本退出.."
exit
fi
is_allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}')
if [ $is_allowed != "+" ]
then
echo "$1 没有开启消息功能"
echo "脚本退出.."
exit
fi
if [ -z $2 ]
then
echo "没有消息发出"
echo "脚本退出.."
exit
fi
whole_msg=$(echo $* | cut -d " " -f 2- )
user_terminal=$(who | grep -i -m 1 $1 | awk '{print $2}')
echo $whole_msg | write $login_user $user_terminal
if [ $? != 0 ]
then
echo "发送失败!"
else
echo "发送成功!"
fi
exit
