bash特性及一些脚本例子

shell01

类似于widnows下批处理文件

bash的特性
gnu bash

自动补全   --多用tab键

历史记录        history
        --!$        --代表上一条命令后面的部分
        --!984        --重复运行第984条命令
        --!useradd    --从下往上匹配,第一个以useradd开头的    
        --CTRL+R键    --进入匹配模式
        ~        --代表家目录
别名功能      alias    unalias
管道
重定向
作业管理        jobs管理
shell编程


变量:
    变量的用途
    1,例$PATH,为了搜索方便
    2,脚本里,使用变量可以引用方便

环境变量:

    
    env    --列举所有的环境变量
    
    set    --环境变量之外的自定义的变量也会列举出来

PS1='[\u@\h \W]\$ '

        \t    24小时格式时间
        \H    完整的主机名
        \v    bash版本


PS1='[\u@\h \W\t]\$ '    --可以修改加上时间
PS1='my server-->'    --也可以直接换成一段字符串    

如果要永久支持,可以放到环境变量的文件
全局
    /etc/profile
    /etc/bashrc

每个用户的家目录下
    ~/.bashrc    
    ~/.bash_profile

        
[root@server4 ~]# locale    --语言有关的变量
LANG=en_US.UTF-8    --主语言的环境
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

上面的变量一般不要去改,如果要改变语言集,可以改下面的文件
    vim /etc/sysconfig/i18n

下面是临时修改的方法
[root@server4 ~]# export LANG=en_US.UTF-8
[root@server4 ~]# export LANG=zh_CN.UTF-8

如果电脑允许注销或者重启,直接在登录的界面选语言集就好了

shell脚本常识:

#!/bin/sh   #!/bin/bash     #!/bin/env bash
    #!  两个字节的魔法字符,在Linux里用来定义文件类型,表示用哪个程序来解释下面的语句
    这是一个不成文的要求

# <comment>
    注释
    <<  可用来多行注释

chmod +x <>.sh
sh <>.sh        bash <>.sh   # 这种情况下, 脚本的#!不再生效

一个优秀的脚本, 除了要优秀地完成任务, 还要有漂亮的代码, 以及有用的帮助, 必要的参数!

shell的变量

不需要申明,弱类型

export定义变量,把自定义变量转化为环境变量
[root@server4 ~]# a=1        --把1赋值给变量a
[root@server4 ~]# echo $a        --看变量的值
1
[root@server4 ~]# bash        --进入子bash环境
[root@server4 ~]# echo $a        --发现查不到变量a
    
[root@server4 ~]# exit        --退出到父bash
exit

[root@server4 ~]# export a=1        --使用export
[root@server4 ~]# echo $a
1
[root@server4 ~]# bash
[root@server4 ~]# echo $a        --再次进入子bash,就可以查看到变量a的值
1


    declare       typeset    --这两个也是定义变量的,都是内部命令
[root@server4 ~]# b=1+1
[root@server4 ~]# echo $b
1+1
[root@server4 ~]# declare -i b=1+1
[root@server4 ~]# echo $b
2


    变量定义的规则:

    1,区分大小写
    2,定义时的格式,等号两边不能有空格,对于有空格的字符串,要用引号引起来
[root@server4 ~]# B=' 3fds  afsa'
[root@server4 ~]# echo $B
3fds afsa
    3,单引号与双引号的,单引的变量或者特殊字符就是为一般字符;但双引内的变量或者特殊字符可以保持它的变量特性

[root@server4 ~]# echo $a
1
[root@server4 ~]# echo '$a'
$a
[root@server4 ~]# echo "$a"
1

    4,变量名可以是字母和数字, _ , 但不能以数字开头
[root@server4 ~]# a1=2
[root@server4 ~]# echo $a1
2
[root@server4 ~]# 1a=3
bash: 1a=3: command not found

    5,变量的获取方式        $变量名    ${变量名}    
[root@server4 ~]# echo ${a}
1
[root@server4 ~]# echo $a
1
    6,取消变量的定义
[root@server4 ~]# unset a
[root@server4 ~]# echo $a
    7,比较特殊的变量定义方式

[root@server4 ~]# a=`which mount`
[root@server4 ~]# rpm -qf $a
util-linux-2.13-0.52.el5

[root@server4 ~]# a=$(which vi)    --小括号
[root@server4 ~]# rpm -qf $a
vim-minimal-7.0.109-6.el5


[root@server4 ~]# read a        --这样主要是由运行脚本的用户去定义变量的值
hello world
[root@server4 ~]# echo $a
hello world

例一:

echo -n 'input your name:'    --echo使用-n参数代表输出之后不换行
read name        
echo "welcome, $name"

read -p "input your name:" name    --read使用-p参数同上一样的效果
echo "welcome, $name"

read -p "input your major:" -t 5 major    --t参数指定输入值的时间只有五秒
echo "$name's major is $major"


read -s -p "input your password:" password --s参数代表隐藏输入    
echo
echo "$name's password is $password"


read -d ';' abc
read -e abc  # readline
read -e -i '/var/log/audit/audit.log' abc   # 给readline指定一个默认值
read -n 2 abc       #只允许输入几个字符
# read -t 3 abc
# echo $abc

# read -e -i '7788' -t 3 abc
7788#
#
# echo $abc

# read -e -i '7788' -t 3 abc
7788
# echo $abc
7788
#


例二:使用普通用户在文本终端模拟root用户登录,并保存root用户的密码

#!/bin/bash

hostnamehead=`hostname |cut -d '.' -f1`
#hostnamehead=`hostname -s`

clear
echo -n "Red Hat Enterprise Linux Server release 5.6 (Tikanga)"
#echo -n `cat /etc/redhat-release`
echo
echo -n "Kernel `uname -r` on an `uname -m`"
echo
echo
read -p "$hostnamehead login:" username
read -s -p "Password:" password
sleep 3
echo
echo "Login incorrect"
echo "$username's password is $password" >> /pub/classNote/ule-scripts/shell/shell01/rootpassword.txt
echo
echo
sh $0

 

-----------------------------------

echo $$     返回程序的PID

echo $0     代表运行的脚本的名字
echo $1        代表运行脚本后接的第一个参数
echo $2        代表运行脚本后接的第二个参数
..............................

echo ${10}

echo $*
echo $@        代表所有参数


echo $?        执行成功则返回0    ,执行失败则返回非0值

例三:
[root@server4 shell01]# cat example01.sh
#!/bin/bash
echo $$
echo $0
echo $1
echo $2
echo $(($1+$2))
echo $*
echo $@
echo $?

[root@server4 shell01]# sh example01.sh 1 2    --用sh命令去执行
[root@server4 shell01]# ./example01.sh 1 2    --./也可以执行,但要执行权限


小练习:
<#>:
    要求用户输入两个数字,然后打印出这两个数的和与差。
   结果类似:
    Input the 1st number: 2
    Input the 2nd number: 7
    Result:
    2+7=9
    2-7=-5

ps.
`bc<<<2+7`
echo '2+7' | bc
echo $[2+7]
echo $((2+7))


例四,
以一个日志文件为例比如说是/var/log/aaa.log
每天备份/var/log/aaa.log并移到专门的备份目录下/backup,并改名有时间标记


#!/bin/bash
#
#backup /var/log/rsyncd.log
#

# copy the log to /work/backup, and rename to 'rsync-`data +%F`.log'
cp /var/log/rsyncd.log /work/backup/rsyncd-$(date +%F).log

# empty the log
:> /var/log/rsyncd.log


之后就是把这个脚本放到计划任务里去执行
01 3  * * *   sh /path/shell.sh

 

 

例五,日志切割脚本
    改进上面的例子
 每天备份/var/log/aaa.log并移到专门的备份目录下/backup的年目录/月目录,并改名有时间标记    ;比如说是2010-09-06号把昨天的日志给移到/backup/2010/09/2010-09-05.aaa.log

        
提示:[root@server4 shell01]# date -d 'yesterday' +'%Y-%m-%d'
2010-09-05

下面是没有变量的情况,看起来非常难受
#!/bin/bash

mkdir /backup/`date -d 'yesterday' +'%Y'`/`date -d 'yesterday' +'%m'` -p

mv /var/log/aaa.log  /backup/`date -d 'yesterday' +'%Y'`/`date -d 'yesterday' +'%m'`/`date -d 'yesterday' +'%Y-%m-%d'`.aaa.log

touch /var/log/aaa.log

例六
改为变量的情况

#!/bin/bash

year=`date -d 'yesterday' +'%Y'`
month=`date -d 'yesterday' +'%m'`
day=`date -d 'yesterday' +'%Y-%m-%d'`

logpath="/backup"    --这里有一点要注意,定义的目录后面有没有/,在引用时最好都加一个/,多个/是没有问题的,少/就有问题了

mkdir -p /backup/$year/$month    --如果目录存在,再建立会报错,加-p参数时可以避免这个报错信息

mv /var/log/aaa.log  $logpath/$year/$month/$day.aaa.log

touch /var/log/aaa.log

eg:
#!/bin/bash
#
#backup /var/log/rsyncd.log
#

oldfile='/var/log/rsyncd.log'
filename="rsyncd-`date -d 'yesterday' +%F`.log"
year=`date -d 'yesterday' +%Y`
month=`date -d 'yesterday' +%m`
bakpath="/work/backup/$year/$month"

mkdir -p $bakpath

cp $oldfile $bakpath/$filename -rf
:> $oldfile


1 0 * * *  bash /work/shell01/backup01.sh

-----------------------------------------------------------

重定向

1,标准输入(stdin);代码为0,  使用<或者<<      --默认设备是键盘        
2,标准输出(stdout);代码为1, 使用>或者>>或者1>或者1>>   --默认设备是屏幕    
3,错误输出(stderr);代码为2, 使用2> 或者 2>>   --默认设备是屏幕

cat > abc.log  <<EOF
...
EOF


    标准输入    ----> 命令    ---->标准输出  -->设备/文件
                 |    
                 |    
                 |
            错误输出
                 |        
                 |
             设备/文件

[a@server4 ~]$ find /home/ -name a    
/home/a            --标准输出
find: /home/aa: Permission denied    --下面全是错误输出
find: /home/user2/.ssh: Permission denied
find: /home/d: Permission denied

find: /home/b: Permission denied
find: /home/c: Permission denied
find: /home/user1: Permission denied
find: /home/smb2: Permission denied
find: /home/g: Permission denied
find: /home/f: Permission denied
find: /home/e: Permission denied
find: /home/bb: Permission denied
find: /home/smb: Permission denied

[a@server4 ~]$ find /home/ -name a > /home/a/find.log --把标准输出重定向到一个文件,所以屏幕显示的是错误输出
find: /home/aa: Permission denied
find: /home/user2/.ssh: Permission denied
find: /home/d: Permission denied
find: /home/b: Permission denied
find: /home/c: Permission denied
find: /home/user1: Permission denied
find: /home/smb2: Permission denied
find: /home/g: Permission denied
find: /home/f: Permission denied
find: /home/e: Permission denied
find: /home/bb: Permission denied
find: /home/smb: Permission denied
[a@server4 ~]$ cat /home/a/find.log

    
[a@server4 ~]$ find /home/ -name a > /home/a/find.log 2> /home/a/finderr.log
--标准输出和错误输出都重定向到不同的文件


[a@server4 ~]$ find /home/ -name a > /home/a/findunion.log 2>> /home/a/findunion.log--标准输出和错误输出都重定向到相同的文件


[a@server4 ~]$ find /home/ -name a > /home/a/findunion.log  2>&1
--标准输出和错误输出都重定向到相同的文件,这种写法比较特殊,最好用这种

[a@server4 ~]$ find /home/ -name a > /dev/null  2>&1    --如果不需要脚本运行过程中的信息,可以扔到/dev/null


双重重定向

[root@server4 ~]# last |tee /home/a/last.txt    --又显示到屏幕,同时还重定向到一个文件


[root@server4 ~]# cat >  cat.txt  <<EOF
> sdfsagweqtg
> dfgdgfdgdse
> dfgsgdfs
ctrl+d          --结束,写脚本时用EOF代替

here document

 

例七;使用EOF实现非shell环境下的命令执行

#!/bin/bash

passwd  <<EOF
newpasswd
newpasswd
EOF


-------------------------------------------------------

管道

grep   cut

[root@server4 shell01]# cat /etc/passwd |grep root

[root@server4 shell01]# cat /etc/syslog.conf |grep -v '^#'|grep -v '^;'|grep -v ^$


cut    --多用于日志截取,对多个空格的处理比较吃力,那种情况就可以使用awk等别的工具
-d 接分隔符
-f 指定分隔后第几列

[root@server4 shell01]# cat /etc/passwd |cut -d : -f7     --显示/etc/passwd文件里以:号分隔的第七列

截取本机的IP
[root@server4 shell01]# ifconfig eth0| grep Bcast |cut -d " " -f2 --发现没有得到结果,因为前面有多个空格

[root@server4 shell01]# ifconfig eth0| grep Bcast |cut -d " " -f12 |cut -d ":" -f2        --但是可以试出来多个空格,这里是-f12
10.1.1.45

[root@server4 shell01]# ifconfig eth0| grep Bcast |cut -d ":" -f2 |cut -d " " -f1        --可以先以:号分隔,再以空格分隔
10.1.1.45


--------------------------------------------


排序统计有关的命令:    wc    sort    uniq

wc
-l    显示行数
-w    显示单词数
-m    显示字符数
默认不加任何参数,就表示相当是上面三个参数都加

[root@server4 shell01]# cat /root/cat.txt |wc
      3       6      39
[root@server4 shell01]# cat /root/cat.txt |wc -l    --这个用得比较广泛
3
[root@server4 shell01]# cat /root/cat.txt |wc -w
6
[root@server4 shell01]# cat /root/cat.txt |wc -m
39

sort 排序

-r    反向排序
-n    以数字来排
-f    大小写不敏感
-t    分隔符   类似cut里的-d
-k    第几列    类似cut里的-f

[root@server4 shell01]# cat /etc/passwd |sort--默认以字母来排序,a-z


[root@server4 shell01]# cat /etc/passwd |sort -r--以字母反向排序


[root@server4 shell01]# cat /etc/passwd |sort -t ":" -k 3  --以:分隔的第三列也就是uid来排序,但是发现不是以数字大小来排,比如说这里  86排到了9的前面

[root@server4 shell01]# cat /etc/passwd |sort -t ":" -k 3 -n  --要加上-n参数,来以数字大小排序


uniq    唯一 (unique)
注意的是:只在连续的范围内去掉重复值,只留一下

[root@server4 shell01]# cat /etc/passwd | cut -d ":" -f 7 |uniq

[root@server4 shell01]# cat /etc/passwd | cut -d ":" -f 7 |sort |uniq


从下面两个看出,顺序的不同,对结果是有很大影响的
[root@server4 shell01]# cat /etc/passwd | cut -d ":" -f 7 |grep bash |uniq
/bin/bash

[root@server4 shell01]# cat /etc/passwd | cut -d ":" -f 7 |uniq |grep bash
/bin/bash
/bin/bash
/bin/bash
/bin/bash

-c参数是count计算统计的意思
[root@server4 shell01]# cat /etc/passwd | cut -d ":" -f 7 |uniq -c
      1 /bin/bash
      4 /sbin/nologin
      1 /bin/sync
      1 /sbin/shutdown
      1 /sbin/halt
      1 /sbin/nologin
      1
     28 /sbin/nologin    --表示一共连续28个/sbin/nologin
      2 /bin/bash
      1 /sbin/nologin
      6 /bin/bash
      1 /sbin/nologin
      6 /bin/bash

 

---------------------------------------------------------------------

命令执行的判断顺序
;
&&
||


[root@server4 shell01]# ./configure ;make ;make install
[root@server4 shell01]# ./configure && make && make install  --这两句结果一样,都是执行前面OK后,再执行后面

注意下面两个符号意义相反
[root@server4 shell01]# ls /test/ && touch /test/1    --前面执行成功,则执行后面

[root@server4 shell01]# ls /test/ || touch /test/2    --前面执行失败,才执行后面


当&&和||混用时,可以替换条件判断语句,但要注意的是逻辑上不要搞乱了
下面要使用&&和||混用来实现
如果/test存在,则输出existed
如果/test不存在,则输出not existed

注意要使用&&再使用||

正常写法:
[root@server4 shell01]# ls /test/ && echo 'existed' || echo 'not existed'
existed

[root@server4 shell01]# ls /testsdfsafa/ && echo 'existed' || echo 'not existed'
ls: /testsdfsafa/: No such file or directory
not existd

错误写法:
[root@server4 shell01]# ls /test/ || echo 'existed' && echo 'not existed'
[root@server4 shell01]# ls /testgsdgsa/ || echo 'existed' && echo 'not existed'
ls: /testgsdgsa/: No such file or directory
existed
not existed


----------------------------------------------------------------


例八:

条件判断:

if 命令 ; then
    动作
fi

if 命令 ; then
    动作
else
    动作
fi


if 命令 ; then
    动作
elif 命令;then
    动作
else
    动作
fi


man test  可以查看很多判断的条件的帮助


文件存在与否和类型的判断
-e    是否存在
-f    是否为文件
-d    是否为目录
-L    是否为链接文件
-p    是否为管道文件
-b    block
-c    character
-S    socket
-s    是否为非空文件

文件权限的判断
-r    是否可读
-w    是否可写
-x    是否可执行
-u    是否有suid,就是前三位是否有s位
-g    是否有sgid
-k    是否有t位

两个文件的比较判断
-nt:    file1 -nt file2  比较file1是否比file2新        
-ot:    file1 -ot file2     比较file1是否比file2旧    
-ef:    比较是否为同一个文件,用于判断硬链接,指向的是同一个innode号


整数之间的判断
-eq    相等
-ne    不等
-gt    大于
-lt    小于
-ge    大于等于
-le    小于等于


字符串之间的判断和比较

-z    是否为空字符串
-n    是否为非空字符串
string1 = string2 是否相等
string1 != string2 是否不等

 

多重条件判断
-a    条件1 -a 条件2    两个条件都满足,才为true
-o    条件1 -o 条件2     两个条件满足其一,就为true


#!/bin/bash

#判断/etc/inittab是否存在
if [ -e /etc/inittab ];then    #注意中括号内的两边要有空格
    echo '/etc/inittab existed'
else
    echo '/etc/inittab not existed'
fi

echo '========================================='

#判断/etc是否为目录
if [ -d /etc ];then
    echo '/etc/ is a directory'
else
    echo '/etc/ is not a directory'
fi

echo '========================================='

#判断/test/1是否为非空文件
if [ -s "/test/1" ];then
    echo '/test/1 is not a empty file'
else
    echo '/test/1 is a empty file'
fi    

echo '========================================='

#判断/tmp目录是否有t位
if [ -k /tmp ];then
    echo '/tmp has a sticky bit set'
else
    echo '/tmp has not a sticky bit set'
fi

echo '========================================='

#判断两个文件的新旧
if [ '/test/1' -nt '/test/2' ];then
    echo '1 is newer than 2'
else
    echo '1 is older than 2'
fi

echo '========================================='

#判断硬连接
if [ /var/spool/mail -ef /var/mail ];then
    echo 'they are hard links'
else
    echo 'they are not hard links'
fi

echo '========================================='

#比较两个数值的大小
if [ 100 -ne 200 ];then
    echo 'the two numbers are not equal'
else
    echo 'the two numbers are equal'
fi

echo '========================================='

#判断是否为空字符串
if [ -z '' ];then    #空格也是为非空,所以空字符串是引号内什么都没有
    echo 'the lenth of string is zero'
else
    echo 'the lenth of string is not zero'
fi

echo '========================================='

#字符串间的比较
if  [  'aBc' != 'abc' ];then
    echo 'the string are not equal'
else
    echo 'the string are  equal'
fi

echo '========================================='
#多重条件判断
if [ -d /etc -o  -e '/test/1' ] ;then
    echo '/etc is a directory and /test/1 existed'
else
    echo '/etc/ is not a directory or /test/1 not existed'
fi

 


-----------------------------------------------------------


题目:

1,交互模式输入一个年份,判断是否为闰年 (被4整除,但不能被100整除,或者能被400整除的就是闰年);熟悉if 结构和 && ||混合使用结构;最好能使用这两种方法写出来


read -p "input the year:" year


if  [ $((year%4)) -eq 0 -a $((year%100)) -ne 0 -o $((year%400)) -eq 0  ];then
                echo 'this is a leap year'
else
                echo 'this is not a leap year'
fi

[[ $((year%4)) -eq 0 &&  $((year%100)) -ne 0 || $((year%400)) -eq 0 ]] && echo OK || echo KO

 

2,交互模式输入一个IP,判断是否能ping通这个IP

echo -n "input a ip address:"
read ip

ping -c 1 $ip >/dev/null 2>&1

if [ "$?" -eq 0 ];then
        echo 'this ip is up!'
else
        echo 'this ip is down!'
fi

 

 

3,交互模式输入一个文件,判断它的类型和权限,输出结果

read -e -p "input a file name:"  file

if [ ! -e "$file" ];then
        echo "$file is not existed or it is not regular file"
        exit 1
fi

if [ -r "$file" ];then
        echo "read=yes"
else
        echo "read=no"
fi


if [ -w "$file" ];then
        echo "write=yes"
else
        echo "write=no"
fi


if [ -x "$file" ];then
        echo "execution=yes"
else
        echo "execution=no"
fi


4, 猜数字的游戏, 输入一个0-99的数字, 判断是否正确(与程序得到的随机数1-99比较)
    提示: $RANDOM  可以取个随机数

 

5. 成绩判断
   让运行脚本的用户输入一个名字和他的成绩,成绩必须是0-100. 否则退出程序,并显示错误信息
   判断用户输入的成绩:
   0-59: 显示"差"
   60-79:显示"良"
   80-100:显示"优"

   显示结果类似:

   用户: 小李飞刀
   成绩: 98
   等级: 优

6,sort,uniq练习
    shell01笔记目录下有一个sortuniq.txt
排成下面的形式
一:
      2 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
      4 news:x:9:13:news:/etc/news:
      6 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
      1 apache:x:48:48:Apache:/var/www:/sbin/nologin
      1 ftp:x:14:50:FTP User:/www:/sbin/nologin

 cat sortuniq.txt |sort|uniq -c |sort -t ":" -k 4 -n


二:
      6 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
      4 news:x:9:13:news:/etc/news:
      2 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
      1 ftp:x:14:50:FTP User:/www:/sbin/nologin
      1 apache:x:48:48:Apache:/var/www:/sbin/nologin

  cat sortuniq.txt |sort|uniq -c|sort -n -r

 

转载于:https://my.oschina.net/u/3251865/blog/839203

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值