shell脚本入门
菜单栏编写方法;
cat << EOF
1)
..............................................................................
2) .....................................................................................
EOF
脚本第一行必须写#!/bin/bash
这一行说明这是一个脚本文件,如果写在第二行,就会认为是一个注释行
vim打开语法高亮:syntax enable
用户交互命令:read -p "提示用户" var
read -p -p是提示,从键盘读取内容放到变量var中。
内置变量:一般大写
$UID是用户ID
用id命令可以查看uid gid 和组
[ $UID -ne 0
]
$UID表示执行这个脚本的UID是多少
查看UID的方法,UID都是在/etc/passwd
tail -5 /etc/passwd
查看配置文件/etc/passwd的最后5行
sync:x:4:65534:sync:/bin:/bin/sync
冒号隔开,第一列是用户名,第二个是密码(x表示有密码),第三个是uid,第四个是gid,
判断语句;
[ 2 -eq 3 ] && echo 0
#中括号两边必须要有空格,-eq是等于的意思,假设2等于3,就会执行后面的echo 0
[ 2 -ne 3 ] && echo 0
#同上,-ne表示不等于。
[ 2 -eq 3 ] && echo 0 || echo 1
#前面的语句执行失败了,将要执行echo 1
gt:是大于;lt 是小于;ge是大于等于;le是小于等于 只能比较数字,不能比较字符串
但是双中括号有时候出问题
[[ $line > 10 ]] && echo 1
#这样用就可以直接用大于号小于号不等于之类的。双中括号。有些系统不支持
[[ $line = 10 ]] && echo 0
比较字符串
一个问题:
#!/bin/bash -
var =xxx
[[ $var = "xxx" ]] && echo 0 || echo 1
用bash执行没有问题,用sh执行出现问题。但是用sh来执行还是会返回正确的结果,或者赋予脚本权限也没问题。双中括号的问题
[[ $var =- ...]] && echo 0 || echo 1
-表示匹配正则的意思。.表示匹配任意的一个字符
vim 加上行号:set nu
[ -z $port ]
判断prot是不是空值
中括号几种常用用法
echo $var
unset $var
取消变量var,相当于var="",把var设置为空
[[ "$var" = "xxx" ]] && echo 0 || echo 1,外面加双引号,这样不会报错
判断是否空值
[ -z $dir ] && echo 0 || echo 1
判断非空
[ ! -z $dir ] && echo 0 || echo 1
判断路径是否存在
[ -d $dir ] && echo 0 || echo 1
路径不存在
[ ! -d $dir ] && echo 0 || echo 1
判断文件是否存在
[ -f cat.sh ] && echo 0 || echo 1
判断文件不存在就在-f前面加一个!就行了。
判断是否有执行权限是-x
shell函数入门
shell的函数不能传参,函数里面的变量和外面的变量都是一样的,不存在局部变量和全局变量等。
#!/bin/bash -
errorinfo(){
echo "error"
}
[ ! -d $dir ] && errorinfo
shell中的位置变量
$0 $1 $2 $# $@
比如./512.sh 1 2 3 4 5
$0 = ./512.sh
$1 = 1
第一个输入参数
$2 = 2 第二个输入参数
$# = 5 一共输入了几个参数
$@ = 1 2 3 4 5
所有的输入值
ping -c 2 -w 2 192.168.1.101
-c表示ping的次数,-w表示超时等待,这里是2秒
标准错误重定向到/dev/null,因为这里已经把标准输入重定向到了/dev/null,所以这里的1就是/dev/null
ping -c 2 -w 2 $ip > /dev/null 2>&1
#exit 1表示退出脚本
#!/bin/bash
[ $# -ne 1 ] && echo 'need $1' && exit 1
ip=$1
echo $ip
#-c表示ping两次,-w指定超时时间,这里是2s。
[ $# -ne 1 ] && echo 'need $1' && exit 1
ip=$1
echo $ip
#-c表示ping两次,-w指定超时时间,这里是2s。
ping -c 2 -w 2 $ip >/dev/null 2>&1
#上一句执行成功$?=0
#上一句执行成功$?=0
[ $? -eq 0 ] && echo "$ip is on"
函数中的位置变量
#!/bin/bash -
test(){
echo "$1"
}
test $1
函数内的位置参数需要通过函数名 参数,这种格式传入进去
[ -z $1 ] && exit 1
判断输入的第一个参数是否为空值,exit 1。返回值是1,用$?可以查看,表示非正常退出
if判断格式
#if后面有个空格,中括号里面两端也有空格,后面还有一个分号,然后then
if [ $i -eq 0 ];then
echo "="
else
echo "!="
fi
如果有多个条件判断,用elif.一定要加then,否则语法错误
if [ $i -eq 0 ];then
echo "="
elif [ $i -eq 1 ];then
echo "1"
else
echo "!="
fi
寻找最近的vi命令,!vi,前面加一个叹号
while循环和for循环
i=0
while [ $i -ne 10 ]
do
i=$(($i+1))
echo $i
done
in后面有几个执行几次
for i in 1 2 3
do
echo
$i
done
for i in `seq 10`
do
echo $i
done
for i in `ls`
do
echo $i
done
#它会cat ls出来的所有目录
for i in `ls`
do
cat $i
done
break和continue用法
#!/bin/bash
i=0
while [ 9 -ne 10 ]
do
i=$(($i+1))
echo $i
[ $i -ge 10 ] && break
#当i大于等于10,就退出循环
done
按行来读取文件
方法一:
#!/bin/bash
cat a.txt |
while read line
do
echo $line
sleep 1
done
方法二;
#!/bin/bash
while read line
do
echo $line
sleep 1
done < a.txt
用for循环,如果一行中间有空格,for会把他作为一个字符串来处理
for line in `cat a.txt`
do
echo $line
sleep 1
done
case条件分支
#!/bin/bash
read -p "Choice:" choice
case $choice in
s|start)
#s或者start都可以
echo 1 ;;
#两个分号表示结尾
2)
echo 2 ;;
3)
echo 3 ;;
*)
echo '*';;
#加个单引号给*,因为它是通配符,不能让它转义
esac
一般在脚本里面要用*和!,如果一定要用,就用单引号引起来。
调试脚本的方法:bash -x case.sh
shell小技巧
&表示继承,这里是继承了标准输出,现在的标准输出是/dev/null
ping -c 2 -w 2 www.baidu.com >/dev/null 2>&1
&是一个通配符,表示任意数字,全部重定向到/dev/null
ping -c 2 -w 2 www.baidu.com &>/dev/null
比较两个文件是否相等:
cmp -s /bin/mv /bin/cp 然后$?,如果是1,说明不相等
diff A文件 B文件
他会显示不同的行
vimdiff这个软件也可以比较
diff a b|grep '>' | cut -d ' ' -f 2
for i in `seq 3`;do echo "789" >> b; done
diff a b | grep '>' | cut -d ' ' -f 2
别名
alias py='python'
cat -n b | tail -1 -n显示行号,tail从后面开始,tail -1,显示最后一行
alias grep='grep --color=auto'
postqueue -p|grep empty
#postqueue邮件列表
转换格式的命令 windows和linux存储文本格式不一致,通过dos2unix命令来进行转换
shell脚本函数库的实现
#!/bin/bash
. 路径/函数脚本
#这样函数库就加载进来了,然后就可以使用了
脚本中的常用计算以及判断变量是否数字的方法
echo $((1+2)) $((1/2)) 不支持浮点
expr 2 + 3 加号前面和后面一定要有空格
调整语言 LANG=en
expr a + 1
echo ? 根据执行结果来判断a是不是字符串
#!/bin/bash
a=asd
expr $a + 1 > /dev/null 2>&1
[ $? -ne 0 ] && echo "$a is not a number" || echo "$a is a number"
shell中打包备份
tar zcvf z:是变成tar.gz c是create v是显示详细过程 f是文件名
tar zcvf etc.tar.gz /etc 打包etc目录为etc.tar.gz压缩文件
bak.sh
#!/bin/bash
logfile=/home/nba/bak.log #日志
riq=`date`
#日期
echo "$riqi" >> $logfile
#追加日期到日志文件
dir=`dirname $logfile` #dirname取出路径名的命令,basename是取出文件名
[ ! -d $dir ] && exit 1 #如果路径不存在,就退出
tar zcvf /home/nba/etc.tar.gz /etc > $logfile 2>>&logfile || exit 2 #如果失败了,退出
mv /home/nba/etc.tar.gc /tmp
date +%Y-%m-%d
#日期
计算期脚本
./clac.sh 1+2
#!/bin/bash
error()
{
#
echo -e "\teg:Usage:`basename $0`
1+2" #-e选项可以加一些\t制表符之类的
printf "\teg:Usage:`basename $0`
1+2\n" #printf默认没有换行,必须加\n
exit 1
}
[ $# -eq 0 ] && error #$#传入的参数个数,假设传入的参数个数为0,就报错
echo $ (($1))
echo -n
#-n选项不支持换行
printf "%9d%9d\n" "10" "9" #10前面有9位
利用getopts来接受参数的正规方法
#!/bin/bash
while getopts ab:c:: ARGS
do
case $ARGS in
a)
echo "a" ;;
b)
b=$OPTARG
echo $b ;;
c)
c=$OPTARG
echo $c ;;
*)
exit 1
esac
done
ping -c 2 www.baidu.com -c是选项,不带-的是参数
getopts :如果一个单个字符后面有一个:,那么这个选项后面必须加一个参数。而且这个参数需要一个空格隔开
如果有两个冒号,就是选项和参数之间不需要间隔,必须紧贴一块
如果没有冒号,就不需要参数。
shift
就是左移,假设sh shift.sh 1 2 3 4 5,第一个参数1会废弃掉,2作为第一个参数,执行两次就左移两次
批量创建用户
#!/bin/bash
for i in `seq 9`
do
id test${i} > /dev/null 2>/dev/null || useradd test${i} #id test${i} id命令是查看这个用户是否存在,如果这个用户不存在就执行useradd命令
echo "passwd{i}"|passwd test${i} --stdin #--stdin:标准输入
echo "user:test${i} pass:$passwd${i}" >> user.log #追加到日志
done
批量创建文件
#!/bin/bash
for i in `seq 10`
do
touch file$i
done
seq -w 10 #会打印01 02 ..... 10
利用find实现批量删除
find ./ -type f -size 0 | xargs rm
find ./ -type f -mtime +1 查1天以前的文件
find ./ -type f -name "*.tar.gz" -mtime +7 | xargs rm 删除七天以前的文件