shell编程笔记
查看目录
tree -i -f | awk '{if(!system("test -d "$1))print $1}'
批量快速创建user
for i in user{0..10}; do useradd $i echo 123456 | passwd --stdin $i done
使用if语句判断
#!/bin/bash #文件判断 if [ -e $1 ]; then echo "file exists" fi if [ -r $1 ]; then echo "readable" fi if [ -w $1 ]; then echo "writable" fi if [ -x $1 ]; then echo "executeable" fi if [ -s $1 ]; then echo "have contents" fi if [ -d $1 ]; then echo "directory" fi if [ -f $1 ]; then echo "file" fi if [ -c $1 ]; then echo "charactor device" fi if [ -b $1 ]; then echo "block device" fi #字符串判断 if [ $1 = "admin" ]; then echo "you are admin" fi if [ $1 != "demon" ]; then echo "you are not demon" fi if [ -z $1 ]; then echo "zero string" fi if [ -n $1 ]; then echo "not empty" fi #数字判断 if test $1 -eq 4; then echo "$1=4" fi if test $1 -ne 4; then echo "$1!=4" fi if test $1 -gt 4; then echo "$1>4" fi if test $1 -ge 4; then echo "$1>=4" fi if test $1 -lt 4; then echo "$1<4" fi if test $1 -le 4; then echo "$1<=4" fi #C语言语法 if (( $1 != 'demon' )); then echo "[C]not demon" elif (( $1 > 5 )); then echo "[C]$1 > 5" fi #更兼容的用法 if [[ $str == "hello" ]]; then echo $str fi if [[ -d $dir ]]; then echo $dir is directory fi
循环 与 选择
#POSIX用法
for ((i=0;i<10;i++)); do if [ $i -eq 5 ]; then continue elif [ $i -eq 9 ]; then break; fi echo $i done read -p "Enter a char: " char case $char in [a-z]|[A-Z]) echo "A letter" ;; [0-9]) echo "A digut" ;; *) echo "function key" ;; esac echo '$#: ' $# echo '$@: ' $@ echo '$*: ' $*
#shift用法 while [ $# -gt 0 ]; do if [[ $str == "" ]]; then str=$1 else str="$str-$1" fi shift done echo $str
数组
#!/bin/bash a="hello" arr=($a 1 2 "c" d) length=${#arr} # 5 arr[5]=$arr echo length is $length # 6 for i in ${arr[@]}; do echo $i done for i in `seq 0 $length`; do # 0 ~ 5 arr[$i]=$i done i=0 while [ $i -lt ${#arr[*]} ]; do echo ${arr[$i]} let "++i" done
函数
function add(){ tot=1 for (( i=1;i<=$1;i++ )); do tot=$(($tot*$i)) done echo $tot } add 6 #720 function sum(){ return $(($1+$2)) } sum 30 40 echo "30 + 40 = $?" echo $$ #pid echo $- #set echo $! #the lastest pid
cut 提取用户名
cut -d: -f1 /etc/passwd
cat /etcpasswd | awk -F: '{print "username: "$1"("$2")"}'
awk 一些常见用法
for i in `awk -F: '{print $1}' /etc/passwd |head` ; dosleep 1 echo $i done for i in `df -Th | awk '{if(NR==2)print int($6)}'`; do echo usage: $i% done df -Th | awk 'END{print "row: "NR "\ncol: "NF}'
测试文件[access.log]
192.168.10.1 root.php 192.168.10.2 bin.php 192.168.10.4 daemon.php 192.168.10.2 adm.php 192.168.10.1 lp.php 192.168.10.1 sync.php 192.168.10.2 shutdown.php 192.168.10.6 halt.php 192.168.10.2 mail.php 192.168.10.2 uucp.php 192.168.10.2 operator.php 192.168.10.3 games.php 192.168.10.4 gopher.php 192.168.10.1 ftp.php 192.168.10.7 nobody.php 192.168.10.2 vcsa.php 192.168.10.4 abrt.php 192.168.10.4 ntp.php 192.168.10.3 saslauth.php 192.168.10.2 postfix.php 192.168.10.3 sshd.php 192.168.10.2 tcpdump.php 192.168.10.3 dbus.php 192.168.10.1 apache.php 192.168.10.8 mysql.php
awk 过滤 192.168.10.1 访问的记录
cat access.log | awk '$1 ~ /192.168.10.1/ {print $0}'
awk 过滤非 192.168.10.1 访问的记录
cat access.log | awk '$1 !~ /192.168.10.1/ {print $0}'
sed 只打印第5行数据
cat passwd |sed -n '5'p
sed 打印第5到8行数据
cat passwd |sed -n '5,8'p
sed 屏蔽第3到20行数据
cat passwd |sed '3,20'd
sed 打印登录用户
cat passwd | sed -n '/bash/'p
sed 显示第一行到包含sync的行
cat passwd | sed -n 1,/sync/p
sed 显示从sshd到最后一行
cat /etc/passwd | sed -n '/sshd/,$'p
uniq 相同合并并统计
cat access.log | awk '{print $1}' | sort | uniq -c
uniq 打印出现超过一次的行
cat access.log | awk '{print $1}' | sort | uniq -d
sort 按字母升序
cat access.log | awk '{print $1}' | sort
sort -r 按字母降序
cat access.log | awk '{print $1}' | sort -r
sort 也可以自己分割文件排序,不用awk, -t指定分隔符默认空格, -k指定按哪一列排序
cat access.log | sort -t: -k1
split 将文件进行分割成多个小文件
split -5 passwd splitname
#ls
#passwd splitnameaa splitnameab splitnameac splitnamead splitnameae
颜色库
#!/bin/bash #name color.sh
#auth demonxian3
da=` echo -e "\033[31m"` #danger su=` echo -e "\033[32m"` #success wa=` echo -e "\033[33m"` #warning pr=` echo -e "\033[34m"` #primary vi=` echo -e "\033[35m"` #violet in=` echo -e "\033[36m"` #info de=` echo -e "\033[37m"` #default cl=` echo -e "\033[0m"` #clear
项目一 目录文件统计
#!/bin/bash
#author demonxian3
line=`tree -i -f .|wc -l` files=`tree -i -f .| head -n $(($line-1))` fileCount=0 dirCount=0 for file in $files; do if [ -d $file ]; then dirCount=`expr $dirCount + 1` ; echo $file else fileCount=`expr $fileCount + 1` fi done echo "Dir:"$dirCount echo "Files:"$fileCount
项目二 文件修改监视器
#!/bin/bash #name filemonitor
#auth demonxian3
len=`tree -i -f | wc -l` len=`expr $len - 1 ` files=`tree -i -f | head -n $len` timestamp=() idx=0 for file in $files; do mtime=`date +%s -r $file` timestamp[$idx]="$mtime#$file" idx=$(($idx+1)) done idx=$(($idx-1)) function check(){ for i in `seq 0 $idx`; do file=${timestamp[$i]:11} oldtime=${timestamp[$i]:0:10} newtime=`date +%s -r $file` if [ $newtime -ne $oldtime ]; then echo "$file has been modified" timestamp[$i]="$newtime#$file" fi done } while true; do check sleep 1 done
项目三 编写系统服务脚本以及实现开机自启
/etc/rc.d/init.d 目录下存放着许多服务脚本, 可以使用service 和 chkconfig 来实现服务关闭开启或者开机自启动
为了方便,系统会制作链接目录链接上面的路径, /etc/init.d/ -> /etc/rc.d/init.d/
如果不想通过chkconfig 来实现开机自启,也可以通过写入启动脚本 /etc/rc.d/rc.local 或者 /etc/rc.d/rc.local 实现自启动
如果想把一个服务脚本改造成 chkconfig 可以识别的启动项,需要在脚本前端添加如下两行
# chkconfig: 2345 90 21 # description: myservicename service daemon
2345表示不指定runlevel等级时运行的默认等级
90表示开启时的顺序 S90开头
21表示关闭时的顺序 K21开头、
只要将脚本放到 /etc/rc.d/init.d下就可以通过services 来启动脚本
项目四 awk 分析apache日志访问记录
#!/bin/bash #[09/May/2018:07:59:32] UsrAgent=$1 cat /var/log/httpd/access_log | awk ' BEGIN{ dan="\033[31m" suc="\033[32m" pri="\033[34m" war="\033[33m" vio="\033[35m" inf="\033[36m" def="\033[37m" cls="\033[0m" usrAgent=$useragent } { if("'"$UsrAgent"'") print vio "user-agent: " $12$13$14$15$16$17$18$19$20$21$22$23$24$25$26$27$28$29$30$31$32 cls len=length($10); len=3-len; while((len--)>0) $10=$10" " len=length($6); len=6-len; while((len--)>0) $6=$6" " print war $1"\t" cls, suc substr($4,5,3)"/"substr($4,2,2)" "substr($4,14,8) cls, substr($6,2,5), $9, $10, inf $7 cls }'
使用方法:
# bash analysis.sh
IP 日期 方法 返回码 长度 访问的页面
查看用户代理
# bash analysis.sh 1
项目五 根据日志404频繁访问进行iptables的封杀, 封杀半个小时
#!/bin/bash # banshell.sh
# [Notice] clear iptables
`iptables -F` #calculate the time for ban time curHour=`date +%H` curMinu=`date +%M` starttime="$curHour:$curMinu" curMinu=$(($curMinu + 30)) if [[ $curMinu -gt 59 ]]; then curHour=$(($curHour + 1)) curMinu=$(($curMinu % 60)) fi stoptime="$curHour:$curMinu" dangerIP=`cat /var/log/httpd/access_log | grep 404 | awk '{print $1}' | sort | uniq -c | awk '{if($1>30)print $2}'` for i in $dangerIP; do res=`iptables -nvL | grep $i` if [[ $res == "" ]]; then `iptables -A INPUT -s $i -m time --timestart $starttime --timestop $stoptime -j DROP ` else echo "go" fi done
项目六 制作操作菜单
通过点可以实现shell文件包含
. shellname.sh
编写菜单
#!/bin/bash #name menu.sh
#auth demonxian3
. color.sh #包含color库 function menu(){ cat << EOF $pr ********************************************* * Operation Menu * ********************************************* $cl $in * * * 1) add a user * * 2) set passwd * * 3) del a user * * 4) select user * * 5) print disk space * * 6) print mem space * * 7) quit * * * ********************************************* $cl EOF } if [[ $0 == "menu.sh" ]]; then menu fi
编写 交互处理 和 逻辑处理
#!/bin/bash #name func.sh
#auth demonxian3
. menu.sh function addUsr(){ read -p "Enter the username: " user read -p "Enter the password: " pass `useradd $user` `echo "$pass" | passwd --stdin "$user" 1>/dev/null` id $user } function setPasswd(){ read -p "Enter the username: " user read -p "Enter the password: " pass echo $pass | passwd --stdin $user 1> /dev/null if [ $? -eq 0 ]; then echo "Successfully" fi } function delUsr(){ read -p "Enter the username: " user `userdel -r $user 1> /dev/null ` if [ $? -eq 0 ]; then echo "successfully" fi } function selectUsr(){ cat /etc/passwd | awk -F: '{ if(NR%4==0) printf("\n"); len=length($1); while(len++<20)$1=$1" " printf($1" ") }END{ printf("\n") }' } function selectDisk(){ df -Th | grep sda | awk 'BEGIN{print "deviceName\tfs\ttotal\tused\tfree\tperc\twhere"}{print $1"\t"$2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7}' } function selectMem(){ free -h | grep -vw "cache" } while true; do clear menu read -p "Input your select: " input case $input in 1) addUsr ;; 2) setPasswd ;; 3) delUsr ;; 4) selectUsr ;; 5) selectDisk ;; 6) selectMem ;; *) echo "Invalid selection" ;; esac read -p "Press any key to continue" done
以下命令将文中所有的字符串idiots替换成managers:
:1,$s/idiots/manages/g
通常我们会在命令中使用%指代整个文件做为替换范围:
:%s/search/replace/g
以下命令指定只在第5至第15行间进行替换:
:5,15s/dog/cat/g
以下命令指定只在当前行至文件结尾间进行替换:
:.,$s/dog/cat/g
以下命令指定只在后续9行内进行替换:
:.,.+8s/dog/cat/g
你还可以将特定字符做为替换范围。比如,将SQL语句从FROM至分号部分中的所有等号(=)替换为不等号(<>):
:/FROM/,/;/s/=/<>/g
在可视化模式下,首先选择替换范围, 然后输入:进入命令模式,就可以利用s命令在选中的范围内进行文本替换。