首页 > 技术文章 > shell编程笔记

demonxian3 2018-05-06 23:53 原文

查看目录

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命令在选中的范围内进行文本替换。

推荐阅读