shell编程(二)

shell编程(二)

Shell脚本编程准备

第一个shell脚本

add 脚本

#! /bin/bash

echo "Please type first number:"
read param1

echo "Please type second number:"
read param2

result=$[$param1+$param2]

echo "The result is: $result"

. helloworld
chmod u+x helloworld
helloworld

shell编程中的变量

shell脚本中的自定义变量

  • 声明 var=2
  • 调用方式 $var
  • 范围:脚本生存期内
赋值,引号的问题
  • 单纯赋值 k=te 可不加引号 或加单引号 或加双引号
  • 赋的值有空格,则必须要加引号
  • 赋的值有其他变量的引用,则 单引号表单纯的句子,双引号表引用. 没空格的话,可不用引号
k4=$k-------
echo $k4
te-------
k4='this $k'
echo $k4
this $k
k4="this $k"
echo $k4
this te
反引号`(~那有)将执行的结果放入变量
:~$ date
Sat Jan 23 19:22:37 CST 2016
:~$ var=`date`
:~$ echo $var
Sat Jan 23 19:22:59 CST 2016

shell 的环境变量

set 查看所有变量
env 查看全局环境变量
1.修改环境变量

  • PATH=$PATH:-shellscript
:~/shellscript$ PATH_SELF=`pwd`     # 自定义变量,范围为当前脚本
:~/shellscript$ echo $PATH_SELF
/home/dr/shellscript
:~/shellscript$ vim envpath    #echo $PATH_SELF
:~/shellscript$ chmod u+x ./envpath
:~/shellscript$ ./envpath   #无输出,PATH_SELF范围为自己脚本
:~/shellscript$ export PATH_SELF    #添加到环境变量,但只可在自己终端看到,在其他终端看不见
:~/shellscript$ ./envpath
/home/dr/shellscript
环境变量的生存期


  1. /etc/profile # 整个系统重启时加载
    /etc/bash.bashrc
    /etc/profile.d/*.sh
  2. home/.bashprofile, home/.bash_login, home/.profile home/.bash_rc

  • 首先读取/etc/profile(PATH/USER/HOSTNAME/HISTSIZE等)
  • 前面的调用 /etc/profile.d/*.sh(颜色,语言,指令别名alias等)
  • ~/.bash_profile, ~/.bash_login, ~/.profile(只依次读取其中一个) 用户调用自己的,不同用户不同
  • ~/.bash_rc, /etc/bashrc
  • source 指令加载脚本的变更(不用重新登录) source .bashrc ,source ~/.bash_rc

  • * 修改/etc/profile*
:~$ env |grep 'PATH'
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
:~$ sudo vim /etc/profile     # PATH=$PATH:~/shellscript
:~$ echo $PATH    # 没加进去
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
:~$ . /etc/profile     # 相当于source 指令加载脚本的变更
:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:~shellscript:/home/dr/shellscript

但再起一个终端则还是没加进去
要重启整个系统(加载了/etc/profile),则无论起多少终端都可看见成功加进去了

* 修改$home/.bashrc*

:~$ vim .bashrc
:~$ . .bashrc
:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/dr/shellscript

再起一个终端发现加进去了。在用户目录下修改的 在bash启动初始化时调用

再起一个终端
:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/dr/shellscript
:~$ /bin/bash
:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/dr/shellscript:/home/dr/shellscript

但执行:~$ /bin/bash 发现又调用了。
* 每次bash启动都调用$home/.bashrc, 在子进程调用多次。*

shell中数学运算

  • expr expression 运算符需转义(\,例如 +),运算符两旁要空格
  • result= [expression]result= [ param1+ param2]

浮点运算 bc

dr@dr-VirtualBox:~$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
100/3
33
scale=4
100/3
33.3333
quit
dr@dr-VirtualBox:~$ var=`echo "scale=4;10/3" |bc`
dr@dr-VirtualBox:~$ echo $var
3.3333

这里写图片描述

Shell编程中的用户输入处理

命令行参数

通过$ 来传递参数

0, 1……, 9, {10},${11}……

#! /bin/bash

echo "the comment is $0"
echo "first number: $1"
echo "first number: $2"
SUM=$[$1+$2]
echo "The result is: $SUM"
:~$ ./shellscript/add 5 7
the comment is ./shellscript/add
first number: 5
first number: 7
The result is: 12
basename 命令只获得脚本名称
  • add: echo basename $0
  • :~$ shellscript/add 5 7
    add
    cal :
#! /bin/bash

name=`basename $0`
if [ $name = 'add' ]
then
        result=$[$1+$2]
elif [ $name = 'minus' ]
then
        result=$[$1-$2]
fi
echo "The $0 result is $result"
:~/shellscript$ ls
cal  envpath  helloworld
:~/shellscript$ ln -s cal add       # 软链接
:~/shellscript$ ln -s cal minus
:~/shellscript$ ls -l
total 12
lrwxrwxrwx 1 dr dr   3 Jan 24 19:28 add -> cal
-rwxrw-r-- 1 dr dr 146 Jan 24 19:19 cal
-rwxrw-r-- 1 dr dr  30 Jan 23 20:45 envpath
-rwxrw-r-- 1 dr dr  31 Jan 24 12:47 helloworld
lrwxrwxrwx 1 dr dr   3 Jan 24 19:28 minus -> cal

:~/shellscript$ ./add 20 10
The ./add result is 30
:~/shellscript$ ./minus 20 10
The ./minus result is 10

永久重定向 exec 文件描述符>filepath

    #! /bin/bash
    exec 1>testoupt  # 这里就把整个脚本的输出都定向了
    exec 2>errlog
    echo "test error" >&2  # 错误信息还需要临时重定向
    echo "normal output 1"
    echo "normal output 2"
    #! /bin/bash
    exec 0< errlog
    count=1
    while raed line
    do
        echo "line #$count : $line"
        count=$[ $count+1 ]
    done
  • $# 参数个数
  • $* 所有参数
  • $@ 参数列表

命令行参数处理

  • shell脚本中 shift 向前移动参数,如 2 1, 1访 1 的值等于以前$2
  • getopt getopts 处理分离参数

在脚本中获取输入—read

处理超时
#! /bin/bash

if read -t 5 -p "Please type your input:" input
then
        echo "you typed : $input"
else
        echo "Timeout"
fi
dr@dr-VirtualBox:~/shellscript$ . read_test1
Please type your input:Timeout
dr@dr-VirtualBox:~/shellscript$ . read_test1
Please type your input:kkk
you typed : kkk
隐藏方式读取

read_test2:

echo "Please input a password:"
read -s passwd
echo "Your password is $passwd"
dr@dr-VirtualBox:~/shellscript$ . read_test2
Please input a password:
Your password is 123
读取文件
使用了重定向

read_test3:

#! /bin/bash

exec 0< read_test1
count=1

while read line
do
        echo "#$count: $line"
        count=$[ $count + 1 ]
done
dr@dr-VirtualBox:~/shellscript$ . read_test3
#1: #! /bin/bash
#2:
#3: if read -t 5 -p "Please type your input:" input
#4: then
#5: echo "you typed : $input"
#6: else
#7: echo "Timeout"
#8: fi
使用管道

read_test3:

#! /bin/bash

count=1

cat read_test1 | while read line
do
        echo "#$count: $line"
        count=$[ $count + 1 ]
done

函数

  • 在脚本中定义函数 add(){}
  • 在终端或其他脚本中引用函数库文件 source filepath ,使用 add 3 4

/test1 两种定义函数格式,return,反引号

    #! /bin/bash
    function func1 {
        echo 'this my first function'
    }
    func1  # 定义之后才能调用
    func2() {
        echo 'This is another function'
        return 20
    }
    func2
    echo "$?"  # 必须在函数执行后立即执行,对退出状态码进行访问,必须在0-255,没有return时默认正确是0,不成功是其他
    value=`func1`  # 将func1的输出赋值给value,这里是用的反引号,命令替换是指shell能够将一个命令的标准输出插在一个命令行中任何位置
    echo "$value"

/test2 函数变量参数的使用

    #! /bin/bash
    add() {
        if [ $# -eq 2 ];then
            result=$[ $1+$2 ]
            echo $result
        else
            echo "Please input 2 params"
            return 1
        fi
    }
    value=`add $1 $2`  # 函数的echo会返回到这里
    if [ $? -eq 0 ]; then  # 判断退出码
        echo $value
    else
        echo "Err: $value"
    fi

/test3 数组参数的处理 局部定义域local

    #! /bin/bash
    testarray(){
        echo "$@"
        echo "$1"
        echo "$2"
        echo "$#"
    }
    sum(){
        local result=0  # 不加local是全局变量
        for var in $@
        do
            result=$[ $result + $var ]
        done
        echo $result
        local newarray=(`echo "$@"`)
        echo ${newarray[*]}  # 返回数组
    }
    array=(1 2 3 4 5 6 7)
    testary $array  # 这里只传进去了第一个参数
    testary ${array[*]}  # 将数组当成了7个参数传了进去
    sum ${array[*]}
    echo "This is outside function: $result"  # 此时访问不到了

函数库:包含了一些列函数的封装,包含可重用函数的脚本文件

    # /calc.sh 函数库文件,加.sh是为了更方便的查找脚本,可以不加
    #! /bin/bash
    add() {
        local result=0
        if [ $# -eq 2 ]; then
            result=$[ $1 + $2 ]
            echo $result
        else
            echo 'Need 2 number params'
            return 1
        fi
    }
    sum(){
        local result=0
        for var in $@
        do
            result=$[ $result + $var ]
        done
        echo $result
    }
    # /test4 测试文件
    #! /bin/bash
    source ./calc.sh  # 将已知文件引入到当前环境
    echo `add 12 23`

bash启动时,自动引入函数库

  • vim ~/.bashrc
  • 在最后添加 . ~/shellscript/calc.sh

条件判断

文件表达式

  • if [ -f file ] 如果文件存在
  • if [ -d … ] 如果目录存在
  • if [ -s file ] 如果文件存在且非空
  • if [ -r file ] 如果文件存在且可读
  • if [ -w file ] 如果文件存在且可写
  • if [ -x file ] 如果文件存在且可执行

整数变量表达式

  • if [ int1 -eq int2 ] 如果int1等于int2
  • if [ int1 -ne int2 ] 如果不等于
  • if [ int1 -ge int2 ] 如果>=
  • if [ int1 -gt int2 ] 如果>
  • if [ int1 -le int2 ] 如果<=
  • if [ int1 -lt int2 ] 如果<

字符串变量表达式

  • if [ a= b ] 如果string1等于string2 字符串允许使用赋值号做等号
  • if [ string1!= string2 ] 如果string1不等于string2
  • if [ -n $string ] 如果string 非空(非0),返回0(true)
  • if [ -z $string ] 如果string 为空
  • if [ $sting ] 如果string 非空,返回0 (和-n类似)

if的格式

    if condition1
    then
        command1
    elif condition2
        command2
    else
        commandN
    fi
    # 下面是实例
    num1=$[2*3]
    num2=$[1+5]
    if test $[num1] -eq $[num2]
    then
        echo '两个数字相等!'
    else
        echo '两个数字不相等!'
    fi

循环

简单for的一个例子,数据四种来源,默认分隔符是空格,换行,制表符 IFS修改分隔符

    #! /bin/bash
    for val in Jan Feb Mar Apr May  # 列表循环
    do
        echo "Month name is $val"
    done
    list="Jan Feb Mar Apr May"
    for val in $list  # 使用变量实现循环
    do
        echo "Month name is $val in list"
    done
    IFS=$";"  # 修改分隔符为;且只有;
    for var in `cat datefile`  # 文件读入,默认分隔符是空格,换行,制表符
    do
        echo "Month name is $val in file"
    done
    for var in ~/shellscript/*  # 也可以是c*  # 可以直接读取文件列表,一定要加通配符
    do  # 等同于 for var in `ls ~/shellscript/*`
        echo "$var"
    done
    for((i=1,j=10;i<=10;i++,j--))  # 类C的结构
    do
        echo "test number is $i $j"
    done

while test command,until test command语句

var=1
while [ $var -lt 10 ]  # command写成[]的形式
do
    echo "$var"
    var=$[ $var+1 ]  # expression 写成$[]的形式
done
var=1
while [ $var -en 10 ]  # command写成[]的形式
do
    echo "$var"
    var=$[ $var+1 ]  # expression 写成$[]的形式
done

shell 脚本的运行控制

Linux的信号

产生信号
  • man 7 sigal 查看对信号的支持
  • 终止进程 Ctrl+C
  • 暂停进程 Ctrl+z (还在进程中,可用 ~$ ps -ef | grep ping 查看)
  • kill 终止进程
  • ps 查看进程
:~$ ps
  PID TTY          TIME CMD
 3027 pts/8    00:00:00 bash
 3045 pts/8    00:00:00 ping
 3046 pts/8    00:00:00 ps
:~$ kill -9 3045    #(-9 无条件终止,PID)
[1]+  Killed                  ping www.baidu.com

运行控制

信号机制 man 7 signal 进行查看 ps kill
  • 组合键产生信号
  • Ctrl + C 终止进程 SIGINT
  • Ctrl + Z 暂停进程 SIGSTP
  • ping www.baidu.com
  • Ctrl + Z
  • ps -ef | grep ping # 可以看到ping命令还在执行中
  • 命令产生信号 kill、killall
  • ps # 查看当前的进程
  • kill -9 25949 # -9是无条件终止,25949是ps命令查出来的PID
  • ps # 刚放的进程已经被终止
脚本中处理信号捕捉 trap
    #!/bin/bash
    trap "echo 'Signal traped SIGINT for Ctrl+C'" SIGINT  # 改变Ctrl + C为 输出文本
    trap "echo 'quit script'" EXIT  # 捕捉退出命令,并修改
    count=1
    while [ $count -le 10 ]
    do
        echo "Loop # $count"
        sleep 1  # 1秒钟的休眠
        count=$[ $count + 1 ]
    done
    trap - EXIT  # 移除添加的trap,不会再输出quit script
    echo 'Loop ended'
/bgtest 后台运行脚本 可以同时执行多个进程 & jobs fg bg nice renice ps al nohup
    # 只需要输入 ./bgtest &
    # nice -n 10 ./bgtest > temp & 后台运行脚本,优先级10(最高-20,最低19)
    # renice 10 -p 19863 通过PID来修改进程的优先级
    # ps al 可以查看进程优先级,普通用户只能最高设置到0
    # nohup ./bgtest & 使脚本的运行与bash无关,可以关掉bash,默认输出到nohup.out
    #!/bin/bash
    trap "echo 'quit script'" EXIT
    count=1
    while [ $count -le 10 ]
    do
        echo "Loop # $count"
        sleep 5
        count=$[ $count + 1 ]
    done
    trap - EXIT
    echo 'Loop ended'
/attest 定时运行脚本 at atq atrm
  • Ubuntu默认没有at命令,sudo apt-get install at
  • at 默认是以邮件的形式发送到指定的邮箱,所以脚本开头有一个标准输出重定向
    # at -M -f ./attest 18:18 M参数指的是不用邮箱,f参数是运行脚本
    # at -M -f ./attest now+2 min
    # atq 会看到at的运行队列
    # atrm 12 通过PID来删除at作业
    #!/bin/bash
    exec 1>>atresult
    echo "script run at `date`"
    echo "end scritp"
启动时运行脚本
系统启动时运行
  • 不同系统启动运行不同,主要有一下两种
  • System V init
  • Upstart init
  • 自定义开机运行脚本
  • debian /etc/init.d/rc.local
  • Ubuntu /etc/rc.local
  • openSUSE /etc/init.d/boot.local
  • CentOS /etc/rc.d/rc.local
  • 在Ubuntu中
  • vim /etc/rc.local 最开始添加调试功能
  • exec 1>>/home/helloworld/logs/startup/logs
  • exec 2>>/home/helloworld/logs/startup/error
  • 后面输入脚本的路径就行了,环境变量要放到另外的脚本,然后引入
shell启动时运行
  • 启动shell的三种方式
  • 启动bash
  • 通过ssh登陆
  • 通过ssh执行命令 直接执行,不会login shell,在man ssh中可以查到
  • 因此,使用ssh执行命令,不会调用/etc/profile指定的设置,只调用/etc/.bashrc这个文件
  • 下面是各种启动shell时调用的文件
  • 启动bash /etc/profile /etc/.bashrc
  • 通过ssh登陆 /etc/profile /etc/.bashrc
  • 通过ssh执行命令 /etc/.bashrc
周期运行脚本 cron crontab anacron
  • vim /etc/crontab 查看cron时效表格式
  • ls /etc/cron* 查看更多的信息,可以添加自己的脚本到指定的文件夹下
  • crontab -l 显示当前用户的时间表
  • crontab -e 修改用户时间表
  • 缺点是默认电脑是7*24小时都开机的,可以用anacron
  • vim /etc/anacrontab 查看格式,最小配置是1天1次
  • 部分转自他人 *
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值