shell脚本编程基础

bash中变量的种类

局部变量:生效范围为当前shell进程,对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
环境变量:生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片段,通常指函数
位置变量:$1,$2,...来表示,用于脚本中调用命令行传递的参数
特殊变量:$?, $0, $*, $@, $#,$$

[root@centos7 ~]# echo $$
4766
[root@centos7 ~]# echo $PPID
4760
[root@centos7 ~]# pstree -p |grep sshd
           |-sshd(1066)-+-sshd(1749)---bash(1764)---vim(8386)
           |            `-sshd(4760)---bash(4766)-+-grep(8672)

局部变量

变量赋值:name=value

变量引用:name="root" name="$USER" name='command' name=$(command)

显示已定义的所有变量:set

删除变量:unset name

[root@centos6 ~]# a=root
[root@centos6 ~]# echo "$a" '$a'
root $a

环境变量

变量赋值:export name=value declare -x name=value

变量引用:$name ${name}

显示所有环境变量:env export

删除变量:unset name

只读和位置变量

只读变量

只能声明,但不能修改和删除,只对当前登录用户有效,退出重进就失效了

声明只读变量: readonly name

查看只读变量:readonly -p

位置变量

在脚本代码中调用命令行传递给脚本的参数

$1, $2, ...:对应第1、第2等参数,shift [n]换位置
$0:位置变量中命令本身
$*:位置变量中传递给脚本的所有参数,全部参数合为一个字符串
$@:位置变量中传递给脚本的所有参数,每个参数为独立字符串
$#:位置变量中传递给脚本的参数的个数
set --:清空所有位置变量

[root@centos6 app]# ./a.sh {0..9}
$1 is:0
$2 is:1
$3 is:2
$4 is:3
$0 is:./a.sh
$10 is:9
$* is:0 1 2 3 4 5 6 7 8 9
$# is:10

()和{}

()的作用:在当前shell下开启一个新空间,shell进程号未变,小括号里面的变量不影响外面,外面的变量可以影响小括号里面。 加小括号的意思是执行一次小括号里面的命令就完事了,所以将来编脚本的时候如果需要用到一次性的任务,不想影响周边的环境,就可以用小括号写法

{}的作用:不开启子shell,将影响当前的shell环境,注意{}的写法,前后有空格,且最后有分号

退出状态

进程使用退出状态来报告成功或失败

0代表成功,非0代表失败

$?:上一次命令执行的情况

exit #:自定义退出状态码,如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

[root@centos6 app]# ping -c1 -W1 172.18.0.1 &> /dev/null ;echo $?
0
[root@centos6 app]# ping -c1 -W1 172.18.0.300 &> /dev/null ;echo $?
2
[root@centos6 app]# ping -c1 -W1 172.18.0.200 &> /dev/null ;echo $?
1

bash中运算和赋值

算数运算

bash中的算数运算:+,-,,/,%(取余数),*(乘方)

let var=算数表达式
var=$[算数表达式]
var=$((算术表达式))
declare –i var=数值
echo '算术表达式' |bc
$RANDOM(0-32767):echo $[$RANDOM%50]

逻辑运算

与(且):第一个为假,结果必定为假;第一个为真,第二个必须要参与运算
或:第一个为真,结果必定为真;第一个为假,第二个必须参与运算
非:!
异或^:异或的两个值,相同为假,不同为真

赋值

var+=1:自加1
var++:自加1
var-=1:自减1
var--:自减1

read

从stdin中读取值,给变量赋值,stdin多余的内容会都赋值给最后一个变量,常用选项:

  • -p:指定要显示的提示
  • -s:静默输入,一般用于密码
  • -n #:指定输入的字符长度
  • -d 'string':指定输入结束符
  • -t number:指定超时时间,单位为秒
[root@centos6 ~]# read a b c
nihao helloworld ccc ddd eee
[root@centos6 ~]# echo "$a|$b|$c"
nihao|helloworld|ccc ddd eee

[root@centos6 ~]# read -p '请输出密码:' passwd
请输出密码:centos
[root@centos6 ~]# echo $passwd
centos

bash中常用的测试命令

条件测试

每条命令系统都会返回执行布尔值,以便用在条件性执行中:0表示真,1表示假

测试命令:注意方括号首尾都有空格

test experssion
[ experssion ]
[[ experssion ]]

条件性的执行操作符

&&:代表条件性的且
||:代表条件性的或

[root@centos6 ~]# ping -c1 -W2 172.18.0.100 &> /dev/null && echo "Succcess" || echo "False"
Succcess
[root@centos6 ~]# ping -c1 -W2 172.18.0.200 &> /dev/null && echo "Succcess" || echo "False"
False
[root@centos6 ~]# ping -c1 -W2 172.18.0.300 &> /dev/null && echo "Succcess" || echo "False"
False

数值测试

-gt:是否大于
-ge:是否大于等于
-eq:是否等于
-ne:是否不等于
-lt:是否小于
-le:是否小于等于

字符串测试

==:是否等于
>:ascii是否大于ascii
<:是否小于
!=:是否不等于

=~:左侧是否包含右侧,此表达式一般用于[[ ]]中,支持扩展的正则表达式

-z “string”:字符串是否为空,空为真,不空为假
-n “string”:字符串是否不为空,不空为真,空为假

文件测试

-a file:同-e
-e file:是否存在,存在为真,不存在为假
-b file:是否存在且为块设备文件
-c file:是否存在且为字符设备文件
-d file:是否存在且为目录文件
-f file:是否存在且为普通文件
-h/-L file:是否存在且为符号链接文件
-p file:是否存在且为命名管道文件
-S file:是否存在且为套接字文件

文件权限测试

-r file:是否存在且可读
-w file:是否存在且可写
-x file:是否存在且可执行
-u file:是否存在且拥有suid权限
-g file:是否存在且拥有sgid权限
-k file:是否存在且拥有sticky权限

文件属性测试

单文件测试

-s file:是否存在且非空
-t file:是否在某终端已经打开
-N file:文件自从上一次被读取之后是否被修改过
-O:当前登录用户是否为文件属主
-G:当前登录用户是否为文件属组

双目测试

file1 -ef file2:file1是否是file2的硬链接
file1 -nt file2:file1是否新于file2(mtime)
file1 -ot file2:file1是否旧于file2

组合测试条件

[root@centos6 ~]# [ -f /bin/cat ] && echo "Success" || echo "False"
Success
[root@centos6 ~]# [ -g /bin/cat ] && echo "Success" || echo "False"
False

bash中防止扩展

\:转义符,使随后的字符按照原意解释
':单引号,强引用,防止所有扩展
":双引号,弱引用,防止所有扩展,以下除外($:变量扩展、`:命令替换、 \:禁止单个字符扩展、!:历史命令替换)

bash的配置文件

全局配置

/etc/profile
/etc/profile.d/*.sh
/etc/bashrc

个人配置

~/.bash_profile
~/.bashrc

配置文件读取顺序

交互式登录:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile--> ~/.bashrc--> /etc/bashrc

非交互式登录::~/.bashrc--> /etc/bashrc--> /etc/profile.d/*.sh

编辑配置文件生效

重新启动shell进程

./source filename:直接重新读取配置文件

~/.bash_logout

在退出登录shell时执行,可以通过编辑此文件实现退出时自动备份和清理临时文件

练习

  1. 编写脚本/root/bin/createscripts.sh,输入createscripts.sh /path/newsh.sh,则会在指定路径生成脚本文件,并涵盖注释信息

    #!/bin/bash
    touch $1
    echo "# -----------------------------------" >> $1
    echo "# Filename:     `basename $1`" >> $1
    echo "# Revision:     1.0" >> $1
    echo "# Date:         `date "+%F"`" >> $1
    echo "# Author:       fanjie" >> $1
    echo "# Email:        [email protected]" >> $1
    echo "# Website:      www.fanjie.com" >> $1
    echo "# Description:  " >> $1
    echo "# -----------------------------------" >> $1
    echo "# Copyright:    2018 fan" >> $1
    echo "# License:      GPl" >> $1
    vim $1
    chmod +x $1
    
  2. 编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名、IPV4地址、操作系统版本、内核版本、CPU型号、内存大小、硬盘大小

    #!/bin/bash
    echo "当前主机系统信息如下: "
    echo "主机名:        `hostname` "
    echo "IPV4地址:      `ifconfig ens33|grep "\(inet\)[[:blank:]]"|tr -s ' '|cut -d' ' -f3`"
    echo "操作系统版本:  `cat /etc/redhat-release |cut -d' ' -f1-4`"
    echo "内核版本:      `uname -r`"
    echo "CPU型号:       `lscpu|grep "^\(Model \)"|tr -s ' '|cut -d' ' -f3-8`"
    echo "内存型号:      `free -m|grep "\(Mem\)"|tr -s ' '|cut -d' ' -f2` MB"
    echo "硬盘大小:      `fdisk -l /dev/sda |grep "^\(Disk /dev/sda\)"|cut -d' ' -f3` GB"
    
  3. 编写脚本/root/bin/backup.sh,可实现将/etc/目录备份到/root/etcYYYY-mm-dd中

    #!/bin/bash
    cp -a /etc/ /root/
    mv /root/etc /root/etc`date +"%F"`
    
  4. 编写脚本/root/bin/disk.sh,显示当前硬盘分区中空间利用率最大的值

    #!/bin/bash
    df |tr -s ' ' %|sort -t% -k5 -nr|head -1|cut -d% -f5
    
  5. 编写脚本/root/bin/links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排序

    #!/bin/bash
    cat /var/log/httpd/access_log|cut -d- -f1|sort|uniq -c|sort -t' ' -k1 -nr
    
  6. 编写脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20用户的UID之和

    #!/bin/bash
    UID10=`cat -n /etc/passwd|grep "^\([[:space:]]*10\)"|cut -d: -f3`
    UID20=`cat -n /etc/passwd|grep "^\([[:space:]]*20\)"|cut -d: -f3`
    echo $UID10+$UID20 |bc
    
  7. 编写脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第x用户和第y用户的ID之和,xy为参数指定

    #!/bin/bash
    UID1=`cat -n /etc/passwd|grep "^\([[:space:]]*$1\)"|cut -d: -f3`
    UID2=`cat -n /etc/passwd|grep "^\([[:space:]]*$2\)"|cut -d: -f3`
    echo $UID1+$UID2 |bc
    
  8. 编写脚本/root/bin/sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和

    #!/bin/bash
    space1=`cat $1 |grep "^[[:space:]]*$"|wc -l`
    space2=`cat $2 |grep "^[[:space:]]*$"|wc -l`
    echo $space1+$space2 |bc
    
  9. 编写脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件

    #!/bin/bash
    etc=$[$(ls -l /etc/ |wc -l)-1]
    var=$[$(ls -l /var/ |wc -l)-1]
    usr=$[$(ls -l /usr/ |wc -l)-1]
    echo $[$etc+$var+$usr]
    
  10. 编写脚本/root/bin/hostping.sh,接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”

    #!/bin/bash
    ping -c1 -W1 $1 &> /dev/null && echo "该IP可访问" || echo "该IP不>可访问"
    
  11. 对以上对该脚本进行升级,可以判断ip地址的合法型,如果不合法,直接提示用户"IP地址不合法"并退出

    #!/bin/bash
    
    
  12. 编写脚本/root/bin/checkdisk.sh,检查磁盘分区空间和inode使用率,如果超过80%,就发广播警告空间将满

    #!/bin/bash
    use1=`df |tr -s ' ' %|sort -t% -k5 -nr|head -1|cut -d% -f5`
    [ $use1 -gt 80 ] && echo "磁盘可用空间超过80%"
    use2=`df -i|tr -s ' ' %|sort -t% -k5 -nr|head -1|cut -d% -f5`
    [ $use2 -gt 80 ] && echo "inode可用空间超过80%"
    
  13. 编写脚本/bin/per.sh,判断当前用户对指定的参数文件,是否不可读并且不可写

    #!/bin/bash
    [ !-r $1 ] && [ !-w $1 ] && echo "this user  can't rw"
    
  14. 编写脚本/root/bin/excute.sh ,判断参数文件是否为sh后缀的普通文件,如果是,添加所有人可执行权限,否则提示用户非脚本文件

    #!/bin/bash
    echo $1 | grep "\.sh$" && chmod +x $1 || echo "非脚本文件"
    
  15. 让所有用户的PATH环境变量的值多出一个路径,例如:/usr/local/apache/bin

    export PATH=$PATH:/usr/local/apache/bin
    将上述文件写入/etc/profile,/etc/profile.d/*.sh,/etc/bashrc
    
  16. 用户root登录时,将命令指示符变成红色,并自动启用如下别名:rm=‘rm –i’

    cdnet=‘cd /etc/sysconfig/network-scripts/’
    

    editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eth0’
    editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eno16777736 或 ifcfg-ens33 ’ (如果系统是CentOS7)

    PS1='\[\e[1;31m\][\u@\h \W]\$\[\e[0m\]'
    将上述文件写入/root/.bashrc或/root/.bash_profile
    
  17. 任意用户登录系统时,显示红色字体的警示提醒信息“Hi,dangerous!”

    echo -e "\033[31mHi,dangerous\!\033[0m"
    将上述文件写入/etc/profile,/etc/profile.d/*.sh,/etc/bashrc
    
  18. 编写用户的环境初始化脚本reset.sh,包括别名,登录提示符,vim的设置,环境变量等

    #!/bin/bash
    cat > /etc/profile.d/env.sh << EOF
    alias cdnet="cd /etc/sysconfig/network-scripts"
    alias editnet="vim /etc/sysconfig/network-scripts/ifcfg-ens33"
    # export PS1="[\[\e[31m\]\u\e[0m\]@\h \W]\\$ "
    export PATH=/app/bin:$PATH
    EOF
    cat > ~/.vimrc << EOF
    set nu
    EOF
    

你可能感兴趣的:(shell脚本编程基础)