Bash脚本编程(原创)

Bash,Unix shell的一種,在1987年由布萊恩·福克斯為了GNU計劃而编写。1989年釋出第一個正式版本,原先是計劃用在GNU作業系統上,但能运行于大多数类Unix系统的操作系统之上,包括Linux與Mac OS X v10.4都將它作為預設shell。它也被移植到Microsoft Windows上的Cygwin與MinGW,或是可以在MS-DOS上使用的DJGPP專案。在Novell NetWare與Andriod在上也有移植。1990年後,Chet Ramey成为了主要的维护者。為Bourne shell的後繼相容版本與開放原始碼版本,它的名稱來自Bourne shell(sh)的一个双关语(Bourne again / born again):Bourne-Again SHell。

Shell中文意思叫做“壳”,在计算机中它是和用户直接交互的一个界面,而我们通常用到的是文本界面的shell:

bash启动的时候会运行各种不同的脚本。当bash作为一个登录的交互shell被调用,或者作为非交互shell但带有--login参数被调用时,它首先读入并执行文件/etc/profile。然后它会依次寻找~/.bash_profile,~/.bash_login,和~/.profile,读入并执行第一个存在且可读的文件。--noprofile参数可以阻止bash启动时的这种行为。当一个登录shell退出时,bash读取并执行~/.bash_logout文件,如果此文件存在。当一个交互的非登录shell启动后,bash读取并执行~/.bashrc文件。这个行为可以用--norc参数阻止。--rcfile file参数强制bash读取并执行指定的file而不是默认的~/.bashrc。如果用sh来调用bash,bash在启动后进入posix模式,它会尽可能模仿sh历史版本的启动行为,以便遵守POSIX标准。用sh名字调用的非交互shell不会去读取其他启动脚本,--rcfile参数无效。当bash以POSIX模式启动时(例如带有--posix参数)它使用POSIX标准来读取启动文件。在此模式下,交互shells扩展变量ENV,从以此为文件名的文件中读取命令并执行。bash会探测自己是不是被远程shell守护程序运行(通常是rshd)。如果是,它会读取并执行~/.bashrc中的命令。但是rshd一般不会用rc相关参数调用shell,也不会允许指定这些参数。

以上是我们对bash的简单介绍,接下来我们就说一下关于bash脚本编写的一些内容,在http://linuxlover.blog.51cto.com/2470728/1631593此篇博客中我提供过几个简单的例子大家可以去看一下。

1、bash中的变量

变量命名规则:

         1.只能包含字母、数字和下划线,并且不能以数字开头

         2.不应与系统中已有的变量重名

         3.最好做到见名知意

1.1、变量:是指在内存中抽出一块空间,然后把这块空间命名,其内部可以放东西,类似一个有名字的容器。

环境变量:即全局变量,变量的作用域为本shell及其子shell。

本地变量:也有人叫全局变量相对局部变量而言,作用范围为整个shell自身。

局部变量:只用关键字local定义,作用范围为某段代码,一般都是在函数体中使用,函数调用结束变量撤销。

位置变量:即代表脚本各参数的位置,$0~$9,一共十个如果多余十个则需要用其他的方法,其中$0代表脚本本身。

特殊变量:具有特殊功能的变量

$# 表示传递到脚本的参数列表

$* 以一个字符串显示所有向脚本传递的参数,跟位置变量不同的是这里参数可超过9个。

$$ 表示当前运行脚本的进程ID号

$! 表示后台运行的一个进程的ID号

$@ 与$#相同,但是使用时加引号,并在引号中返回每一个参数

$- 显示shell使用的当前选项,与set命令相同

$? 显示最后命令运行的推出状态,0表示没有错误,其他任何值表示有错误

数值型:整型、浮点型

字符型:字符、字符串

布尔型:真、假

1.2、与变量相关的一些命令

declare 创建或显示变量

        参数-f 只显示函数名

        参数-r 创建只读变量(typeset也可以)

        参数-x 创建转出变量

        参数-i 创建整数变量

        如果参数中使用+来代替-,表示选项的含义相反。

export 创建环境变量

        参数– 表明选项结束,所有后面的参数都是实参

        参数-f 表示在”变量-值”对照中的变量是一个函数名

        参数-n 表示把全局变量转换成局部变量(也就是本地变量)。

        参数-p 显示全局变量列表

readonly 创建或显示只读变量

        参数– 表示选项结束

        参数-f 创建只读变量

set 设置或者重设各种shell

shift [n] 用来移动或调整位置变量,使$4赋给$3(也就是全都向前面移动一次),这个里面的n表示移动几位,默认是移动一位。

typeset 这个就跟declare相同了

unset 清除变量的定义

        参数– 表示选项结束

        参数-f 删除只读变量,但是不能sehll环境中制定的变量和函数。

read 用于从终端或者文件中读取输入,它读取整行输入,而末尾的换行符被翻译成 null(空字符串)。如果没有指定名称,读取的行就被赋值到特定的变量 REPLY 中。同时,read 命令还可以用来使程序暂时停下来等待用户输入回车。

        -a array 将单词清单放入 array 数组中

        first last 读取输入到第一个空格或回车,将输入的第一个单词放入 first 中,而其他的则放在 last 中

        -p prompt 打印提示,等待输入,并将输入存入 REPLY 中

        -r line 允许输入中包含反斜杠 ”\ ”

        -t timaout:指定等待接受参数的时间

        -n:表示不换行

1.3、变量替换

2、bash中的运算

2.1、算数运算:需要变量为数值型,但默认直接进行变量赋值时都是字符型,所以需要显示的定义可以使用declare或let命令。但bash是解释型语言(还有编译型语言),所以变量的定义非常宽泛,在定义时可以不不指明变量类型,使用时在指明就可以了。

算术运算符:

+:加

-:减

*:乘

/:整

%:取模

**:幂

运算方法:

let c=$a+$b

c=$[$a+$b]

c=$(($a+$b))

c=$(expr $a + $b) | c=`expr $a + $b`

2.2、逻辑运算:即与、或、非以及条件测试运算。

命令间的逻辑关系:

         逻辑与:&& 有一个为假,结果为假

                   第一个条件为假时,第二个条件不再判断;

                   第一个条件为真时,第二个条件必须判断;

         逻辑或:|| 有一个为真,结果为真

                   第一个条件为真时,第二个条件不再判断;

                   第一个条件为假时,第二个条件必须判断;

         逻辑非:!

条件测试类型:

         整数测试

         字符测试

         文件测试

条件测试的表达式:

         [ expression ]  命令测试法  表达式

         [[ expreession ]]  关键字测试法

         test expression

整数比较(双目操作):

         -eq:测试两个整数是否相等,如:[ $a -eq $b ] 测试a,b两个变量中的数是否一致,一致状态返回值为0 echo $?

         -ne:测试两个整数是否不等,不等为真,相等为假

         -gt:测试一个数是否大于另一个数,大于为真,否则为假

         -lt:测试一个数是否小于另一个数,小于为真,否则为假

         -ge:大于或等于

         -le:小于或等于

文件测试:

-a file exists.

-b file exists and is a block special file.

-c file exists and is a character special file.

-d file exists and is a directory.

-e file exists (just the same as -a).

-f file exists and is a regular file.

-g file exists and has its setgid(2) bit set.

-G file exists and has the same group ID as this process.

-k file exists and has its sticky bit set.

-L file exists and is a symbolic link.

-n string length is not zero.

-o Named option is set on.

-O file exists and is owned by the user ID of this process.

-p file exists and is a first in, first out (FIFO) special file or named pipe.

-r file exists and is readable by the current process.

-s file exists and has a size greater than zero.

-S file exists and is a socket.

-t file descriptor number fildes is open and associated with a terminal device.

-u file exists and has its setuid(2) bit set.

-w file exists and is writable by the current process.

-x file exists and is executable by the current process.

-z string length is zero.

字符测试:字符串比较

双目:

>: 大于则为真

<: 小于则为真

>=:大于等于则为真

<=:小于等于则为真

==:等于则为真

!=:不等于则为真

单目:

-n String: 是否不空,不空则为真,空则为假

-z String: 是否为空,空则为真,不空则假

3、条件测试语句和循环语句

3.1、if语句

格式:

(1) 一般

if command

then

command(s)

fi

(2)test 模式

if test expression

then

command(s)

fi

if [ string/numeric expression ]

then

command(s)

fi

if [[ string exprssion ]]

then

command(s)

fi

(3)let 模式

if (( numeric expression ))

then

command(s)

fi

嵌套 if 命令:

格式:

if command

then

command(s)

else

command(s)

fi

if/elif/else 命令:

格式:

if command

then

command(s)

elif command

then

command(s)

…………

else

command(s)

fi

3.2、case 语句

case 值中允许出现 shell 通配符和竖线(|)作为 OR 操作符。*) 的作用相当于 else语句。

格式:

case variable in

value1)

command(s)

;;

value2)

command(s)

;;

………………

*)

command(s)

;;

esac

4、循环语句

4.1、for循环

格式:

for variable in word_list

do

command(s)

done

写成一行:

for var in item1 item2 ... itemN; do command1; command2… done;

C风格的形式:

for (( EXP1; EXP2; EXP3 ))

do

    command1

    command2

    command3

done

4.2、while循环

格式:

while condition

do

    command

done

特殊用法:遍历文件的每一行

while read VAR_NAME; do

    command(s)

done < /path/to/somefile

4.3、until循环

until 的用法跟 while 的类似,只是在 until 后面的语句为假的时候执行循环体。

格式:

until command

do

command(s)

done

4.4、无限循环

while :

do

    command

done

或者

while true

do

    command

done

或者

for (( ; ; ))

或者

until false; do

      command

done

4.5、循环中的控制语句

(1)break 命令:

用来从循环中强行退出,但不退出程序。Break 后加一个数字可用来指定 break 强行退出的循环的层数。其中,最外面的循环数是 1,依次往里是 2、3……

格式:

break [n]

(2)continue 命令:

如果某些条件为真,continue 就控制跳转到循环的顶部,所以 continue 后面的语句将被忽略。Continue 后加一个数字可控制跳转到任何层的循环顶部重新开始执行。其中,最内的循环、号是 1,往外依次是 2、3……

格式:

continue [n]

(3)shift 命令:

用来把参量列表位移指定次数,没有参数的 shift 把参量列表向左移动一位。一旦位移发生,被位移出列表的参数就被永远删除了。通常在 while 循环中,shift 用来读取列表中的参量。

格式:

shift [n]

5、函数:函数本身就是一个命令或一组命令的名字。函数可以使程序模块化,提高效率,可以就在当前的 shell 环境中执行,即在执行像 ls 等可执行程序时不产生自进程。

使用函数的规则:

1、shell 总是先执行别名,然后是函数、内建命令,最后才执行可执行程序。

2、函数使用前必须先定义。

3、函数在当前环境下执行,它和调用它的脚本分享变量,并通过位置参量传递参数。通过 local 函数可以在函数内部建立本地变量。

4、如果在函数中使用 exit,则可以退出整个脚本,而退出函数则只是返回到调用函数的地方。

5、return 命令返回函数中最后一个命令的退出状态值或者是给定的参数值。

6、使用 export -f 可以将函数输出到子 shell。

7、使用 declare -f 可显示定义的函数清单,而 declare -F 则只显示函数的名字。

8、函数内部的陷阱是全局的,它们可以被脚本和脚本激活的函数共享。如果一个陷阱被定义为函数,它就可以被脚本共享,但可能产生意想不到的效果。

9、如果函数保存在其他文件中,必须通过 source 或者 dot 命令把它们装入当前脚本。

10、函数可以递归,且其递归次数没有限制。

5.1、函数定义

(1)构建函数

格式:

function function_name { comand(s); command(s); }

(2)复位函数:使用 unset 命令将函数从内存中删除。

格式:

unset -f function_name

(3)输出函数:输出到给子 shell。

格式:

export -f function_name

5.2、函数参数和返回值

(1)内建 local 函数:

local 创建的变量只在函数内部使用,退出函数变量即实效。

(2)参数:

通过位置参量可以向函数传递参数,该参数不会影响函数外使用的任何位置参量。

(3)内建 return 函数:

return 用来退出函数并返回到调用函数的地方。如果没有给 return 指定参数,返回的函数值就是最后一行的退出状态值。Return 返回的值只能是 0~256 之间的整数,且该值保存在“ ?”中,同时可以使用命令替换来捕捉函数的输出,即把整个函数放在括号内,前面加$(即:$(function_name)),或者通过引号把输出赋值给一个变量。

5.3、source(或者 dot)命令

函数通常被定义到.profile 中,当需要使用函数时,可以使用 source 或者 dot 加文件名来激活这些在文件中定义的函数。此命令也经常用在bash脚本的开头出以读取配置文件,获取其中的变量值。

7、陷阱信号

当程序运行时,按下 Control-C 或者 Control-/后程序就立刻终止,但很多时候当不希望信号到达时程序就立刻停止运行,而是希望忽略这个信号继续运行下去或者在程序退出前做些清除操作。这些可以通过 trap 命令来控制程序在收到信号以后的行为。信号是由一个进程发送给另外一个进程的,或者在特定的键按下以后由操作系统发送给进程的,又或者在异常情况下发生时,由数字组成的非同步的消息。Trap 命令告诉 shell 根据收到的信号而以不同的方式终止当前的进程。如果 trap 后面跟着一个用引号引用的命令,则在接收到指定的信号数字时就执行这个命令。Shell 共读取两次命令字符串,一次是在设置 trap 时,一次是在信号到达时。如果命令字符串被双引号引用,在第一次 trap 设置时就执行变量和命令替换。如果是用单引号引用,那么等到信号到达 trap 开始执行时,才运行变量和命令替换。

格式:

trap 'command;command' signal_number

trap 'command;command' signal_name

eg:

trap 'rm tmp*;exit 1' 0 1 2 15

trap 'rm tmp*;exit 1' EXIT HUP INT TERM

注:当 1(挂起)、2(中断)或者 15(软件终止)任何一个信息到达时就执行 rm 并 exit。

 

Bash 允许在信号上使用象征性名称,例如没有前缀(SIG)或者用数字作为信号的名称。一个叫做 EXIT 的或者数字 0 的伪信号,将在 shell 退出时,导致一个陷阱的执行。

(1)信号复位:

trap 后面加一个信号或者数字,可把信号复位为默认动作。一旦调用了函数,函数设置的陷阱可以被调用这个函数的 shell 识别。同时,在函数外设置的陷阱也可被函数识别。

Eg: trap 2 或者 trap INT,表示恢复当 Control-C 按下就杀死当前进程的默认动作。

trap ‘trap 2’ 2 表示用户必须按两次 Control-C 才能终止程序,其中第一个陷阱捕捉信号,第二个复位信号默认动作为杀死进程。

(2)忽略信号:

如果 trap 后面跟一对空括号,列表中的信号将被进程忽略。

Eg: trap " " 1 2 or trap " " HUP INT

注:信号 1、2 将被 shell 进程忽略。

(3)陷阱列表:

通过 trap 命令可显示陷阱列表和分配给陷阱的命令清单。

Eg:

[root@localhost root]# trap 'echo hehe!;exit 1' 2

[root@localhost root]# trap

trap -- 'echo hehe!;exit 1' SIGINT

(4)函数中的陷阱:

如果使用陷阱处理函数中的信号,一旦函数被激活,它将影响整个脚本,即陷阱对于脚本来说是全局的。

6、数组:

         数组:变量阵列,通过同一个名字进行存取操作;

                   连续的多个独立的内存空间(元素),每个内存空间相当于一个变量;

                  bash的数组支持稀疏格式;

                   数组元素:数组名[索引]

                            索引:从0开始编号

         声明数组:

                   declare -a Array_Name

关联数组:

                   bash从4.0版本起支持关联数组:数组索引可为自定的字符串;

declare -A ARRAY_NAME

6.1、数组元素赋值:

                   (1) 一次只赋值一个元素

                            a_name[index]=value

                            weekday[0]="Sunday"

                            weekday[1]="Monday"

                   (2) 一次赋值全部元素

                            weekday=("Sunday" "Monday" "Tuesday")

                   (3) 指定索引进行赋值

                            weekdays=([0]="Sunday" [3]="Thu" [6]="Sat")

                   (4) read -a a_name

         引用数组元素:${array_name[index]}

         获取数组长度:${#array[*]}, ${#array[@]}

                   即数组中元素的个数;

6.2、数组切片:从数组中挑选指定的某个或某些元素:

                            ${array[@]:offset:number}

                                     offset: 偏移的元素的个数;

                                     number:要取出的元素的个数;

                            ${array[@]:offset}

                                     取出偏移量之后剩余所有的元素;

                            ${array[@]}

                   从数组中删除元素:

                            unset array[index]

7、bash的字符串处理:

7.1、字符串切片:${var:offset:length}

         取出字符串的最后几个字符:${var: -length}

                   注意:-length之前有空白字符;

7.2、基于模式取子串:

         ${var#*word}:自左而右,查找var变量中存储的字符串中第一次出现的由word所指明的字符,删除此字符及其左侧的所有内容;

         ${var##*word}:自左而右,查找var变量中存储的字符串中最后一次出现的由word所指明的字符,删除此字符及其左侧的所有内容;

         ${var%word*}:自右而左,查找var变量中存储的字符串中第一次出现的由word所指明的字符,删除此字符及其右侧的所有内容;

         ${var%%word*}:自右而左,查找var变量中存储的字符串中最后一次出现的由word所指明的字符,删除此字符及其右侧的所有内容;

示例:

         url="http://www.magedu.com:80"

         取端口:echo ${url##*:}

         取协议:echo ${url%%:*}

7.3、查找替换:

         ${var/pattern/replacement}:查找var变量存储的字符中第一次由pattern匹配到的内容,并替换为replacement;

         ${var//pattern/replacement}:查找var变量存储的字符中所有能够由pattern匹配到的内容,并替换为replacement;

         ${var/#pattern/replacement}:查找var变量存储的字符中最开始处能够由pattern匹配到的内容,并替换为replacement;

         ${var/%pattern/replacement}:查找var变量存储的字符中最后位置能够由pattern匹配到的内容,并替换为replacement;

7.4、查找删除:

         ${var/pattern}:查找var变量存储的字符中第一次由pattern匹配到的内容,并删除;

         ${var//pattern}:查找var变量存储的字符中所有能够由pattern匹配到的内容,并删除;

         ${var/#pattern}:查找var变量存储的字符中最开始处能够由pattern匹配到的内容,并删除;

         ${var/%pattern}:查找var变量存储的字符中最后位置能够由pattern匹配到的内容,并删除;

7.5、字符串大小写转换:

         ${var^^}:把var变量中的所有小写字母,统统替换为大写;

         ${var,,}:把var变量中的所有大写字母,统统替换为小写;

8、shell运行调试

脚本的调试可用 bash 或 set 命令来实现。Bash 或 set 跟踪调试时,执行脚本中的每行都会在前面加一个(+)号。

 

9、其它补充

9.1、特殊含义字符汇总

9.2、mktemp命令:

mktemp [OPTIONS] filename.XXX

-d: 创建临时目录

--tmpdir=/path/to/somewhere :指定临时文件所在的目录

mktemp /tmp/tmp.XXX                    #XXX生成相同数量随机字符

mktemp --tmpdir=/tmp tmp.XXX       #指定目录创建临时文件

mktemp --tmpdir=/tmp -d tmp.XXX    #指定目录创建临时目录

9.2、install命令:

install [OPTIONS] SOURCE DEST

install [OPTIONS] SOURCE... DIR

install [OPTIONS] -d DIR ...

增强型的复制命令:

-o OWNER

-g GROUP

-m MODE

-d : 创建目录

install /etc/fstab /tmp                 #复制文件到指定目录

install --mode=644 /etc/issue /tmp/     #复制时指定权限

install --owner=czc /etc/issue /tmp #复制时指定属主

install --group=czc /etc/issue /tmp #复制时指定属组

install -d /tmp/hello                 #创建目录

10、一些实例

练习:写一个脚本

从键盘让用户输入几个文件,脚本能够将此几个文件归档压缩成一个文件;

#!/bin/bash

#

read -p "Please input tarname:" TAR

read -p "Please input filename:" FILE

read -p "Compress [gzip|bzip2|xz]:" COM

case $COM in

gzip)

         tar -zcf ${TAR}.tar.gz $FILE ;;

bzip2)

         tar -jcf ${TAR}.tar.bz2 $FILE ;;

xz)

         tar -cf ${TAR}.tar $FILE

         xz ${TAR}.tar ;;

*)

         echo "Unkown."

         exit 8 ;;

esac

 

写一个脚本:

1) 显示一个菜单给用户:

d|D) show disk usages.

m|M) show memory usages.

s|S) show swap usages.

*) quit.

2) 当用户给定选项后显示相应的内容;

  

扩展:

         当用户选择完成,显示相应信息后,不退出;而让用户再一次选择,再次显示相应内容;除了用户使用quit;

#!/bin/bash

#

while ! who | grep "hadoop" &> /dev/null;do

         sleep 5

         echo "The user hadoop does not loggin."

done

echo "Hadoop loggin."

[root@localhost ~]#

[root@localhost ~]# cat slectshow.sh

#!/bin/bash

#

cat << EOF

d|D) show disk usages.

m|M) show memory usages.

s|S) show swap usages.

q|quit) exit.

EOF

read -p "Please input your chioce:" CHO

while [ $CHO != 'quit' ];do

         case $CHO in

                   d|D)

                            df -h ;;

                   m|M)

                            free -m | grep  "Mem" ;;

                   s|S)

                            free -m | grep  "Swap" ;;

                   q|quit)

                            exit 0 ;;

                   *)

                            echo "Your chionce must be in:"

                            cat << EOF

                            d|D) show disk usages.

                            m|M) show memory usages.

                            s|S) show swap usages.

                            q|quit) exit.

EOF

                   esac

                   read -p "Please input your chioce:" CHO

done

 

写一个脚本(前提:请为虚拟机新增一块硬盘,假设它为/dev/sdb),为指定的硬盘创建分区:

1、列出当前系统上所有的磁盘,让用户选择,如果选择quit则退出脚本;如果用户选择错误,就让用户重新选择;

2、当用户选择后,提醒用户确认接下来的操作可能会损坏数据,并请用户确认;如果用户选择y就继续,n就退出;否则,让用户重新选择;

3、抹除那块硬盘上的所有分区(提示,抹除所有分区后执行sync命令,并让脚本睡眠3秒钟后再分区);并为其创建三个主分区,第一个为20M,第二个为512M, 第三个为128M,且第三个为swap分区类型;(提示:将分区命令通过echo传送给fdisk即可实现)

  1 #!/bin/bash

  2 #

  3 fdisk -l 2> /dev/null | grep "^Disk /dev/[sh]d[a-z]"

  4 read -p "Please input your choice:" DEV

  5 until fdisk -l 2> /dev/null | grep "^Disk /dev/[sh]d[a-z]" | grep "^Disk $DEV" &> /    dev/null;do

  6         if [ $DEV == 'quit' ];then

  7                 echo "Quiting..."

  8                 exit 8

  9         fi

 10         read -p "Please input your choice agin:" DEV

 11 done

 12 read -p "Next choice maybe delete all the data in $DEV,are you sure?(y|n)" CHO

 13 until [ $CHO == 'y' -o $CHO == 'n' ];do

 14         read -p "Please choice agin.Next choice maybe delete all the data in $DEV,a    re you sure?(y|n)" CHO

 15 done

 16 if [ $CHO == "n" ];then

 17         echo "Quiting..."

 18         exit 9

 19 else

 20         for i in ` mount | grep "$DEV" | awk '{print $1}'`;do

 21                 fuser -mk $i

 22                 umount $i

 23                 echo "$i unmount ok."

 24         done

 25         dd if=/dev/zero of=$DEV bs=512 count=1 &> /dev/null;

 26         sync

 27         sleep 3

 28         echo 'n

 29         p

 30         1

 31

 32         +5G

 33         n

 34         p

 35         2

 36

 37         +5G

 38         n

 39         p

 40         3

 41

 42         +5G

 43         t      

 44         3      

 45         82

 46         w

 47         ' | fdisk $DEV

 48         partprobe $DEV

 49         sync

 50         sleep 2

 51         mke2fs -j ${DEV}1

 52         mke2fs -j ${DEV}2

 53         mkswap ${DEV}3

 54 fi

 

写一个脚本,完成以下功能:

说明:此脚本能于同一个repo文件中创建多个Yum源的指向;

1、接受一个文件名做为参数,此文件存放至/etc/yum.repos.d目录中,且文件名以.repo为后缀;要求,此文件不能事先存,否则,报错;

2、在脚本中,提醒用户输入repo id;如果为quit,则退出脚本;否则,继续完成下面的步骤;

3、repo name以及baseurl的路径,而后以repo文件的格式将其保存至指定的文件中;

4、enabled默认为1,而gpgcheck默认设定为0;

5、此脚本会循环执行多次,除非用户为repo id指定为quit;

  1 #!/bin/bash

  2 #

  1 if [ -e /etc/yum.repos.d/$1.repo ] || [  -z $1 ];then

  2         echo "$1 exist or error."

  3         exit 9

  4 fi

  5 while [ -n $1 ];do

  6 read -p "Please input repo_id:" RID

  7 if [ $RID == quit ];then

  8         echo "Quiting...."

  9         exit 0

 10 else

 11         touch /etc/yum.repos.d/$1.repo

 12         read -p "Please input name:" NAM

 13         read -p "Please input baseurl:" BSU

 14         read -p "please input enabled:" ENB

 15                 if [ -z $ENB ];then

 16                         ENB=1

 17                 fi

 18         read -p "Please input gpgcheck:" GPG

 19                 if [ -z $GPG ];then

 20                         GPG=0

 21                 fi

 22 fi

 23 echo "[$1]

 24 name=$NAM

 25 baseurl=$BSU

 26 enabled=$ENB

 27 gpgcheck=$GPG" >> /etc/yum.repos.d/$1.repo

 28 done

 

写一个脚本,完成如下功能:

说明:此脚本能够为指定网卡创建别名,则指定地址;使用格式如:mkethalias.sh -v|--verbose -i ethX

1、-i选项用于指定网卡;指定完成后,要判断其是否存在,如果不存在,就退出;

2、如果用户指定的网卡存在,则让用户为其指定一个别名,此别名可以为空;如果不空,请确保其事先不存在,否则,要报错,并让用户重新输入;

3、在用户输入了一个正确的别名后,请用户输入地址和掩码;并将其配置在指定的别名上;

4、如果用户使用了-v选项,则在配置完成后,显示其配置结果信息;否则,将不显示;

 

  1 #!/bin/bash

  2 #

  3 V=0

  4 until [ $# == 1 ];do

  5 case $1 in

  6         -i)

  7                 if ifconfig | grep "$2" &> /dev/null ;then

  8                         read -p "Please input an alias:" ALS

  9                         while ifconfig | grep "$ALS" &> /dev/null;do

 10                                 echo "This alias is exist."

 11                                 read -p "Please input an alias agin:" ALS

 12                         done

 13                         read -p "The IP address:" IPADD

 14                         read -p "The MASK(0-32):" MASK

 15                 else

 16                         echo "This dev does not exist."

 17                         exit 8

 18                 fi

 19                 shift 1;;

 20         -v|--verbose)

 21                 V=1

 22                 shift 1;;

 23 esac

 24 done

 25 ip addr add $IPADD/$MASK dev $1 label $ALS

 26 if [ $V == 1 ];then

 27         ip addr show $1

 28 fi

 

5、创建/etc/rc.d/init.d/network服务脚本

  1 #!/bin/bash

  2 #

  3 #chconfig: 35 09 90                                     #设定启动级别3|5,启动优先级09,关闭优先级90

  4 #description: network service       #描述信息

  5 . /etc/rc.d/init.d/functions   #读取functions函数文件

  6 prog=network

  7 CONF=/etc/sysconfig/network-scripts/ifcfg-eth0

  8 . $CONF

  9 NETMASK=24

 10 start() {

 11         ifconfig eth0 $IPADDR/$NETMASK up

 12         [ -z $GATEWAY ] && route add default gw $GATEWAY

 13 }

 14

 15 stop() {

 16         ifconfig eth0 down

 17 }

 18

 19 status() {

 20         ifconfig eth0

 21 }

 22

 23 usage() {

 24         echo "Usage:$prog {start|stop|restart|status}."

 25 }

 26

 27 case $1 in

 28 start)

 29         start

 30         success "Config network eth0"

 31         ;;

 32 stop)

 33         stop

 34         success "Stop network card eth0"

 35         ;;

 36 restart)

 37         stop

 38         start

 39         sucess "Restart network card eth0"

 40         ;;

 41 *)

 42         usage

 43         exit 1

 44         ;;

 45 esac

 

复制二进制程序及其依赖的库文件的脚本:

#!/bin/bash

#

DEST=/mnt/sysroot

libcp() {

  LIBPATH=${1%/*}

  [ ! -d $DEST$LIBPATH ] && mkdir -p $DEST$LIBPATH

  [ ! -e $DEST${1} ] && cp $1 $DEST$LIBPATH && echo "copy lib $1 finished."

}

 

bincp() {

  CMDPATH=${1%/*}

  [ ! -d $DEST$CMDPATH ] && mkdir -p $DEST$CMDPATH

  [ ! -e $DEST${1} ] && cp $1 $DEST$CMDPATH

 

  for LIB in  `ldd $1 | grep -o "/.*lib\(64\)\{0,1\}/[^[:space:]]\{1,\}"`; do

    libcp $LIB

  done

}

 

read -p "Your command: " CMD

until [ $CMD == 'q' ]; do

   ! which $CMD &> /dev/null && echo "Wrong command" && read -p "Input again:" CMD && continue

  COMMAND=` which $CMD | grep -v "^alias" | grep -o "[^[:space:]]\{1,\}"`

  bincp $COMMAND

  echo "copy $COMMAND finished."

  read -p "Continue: " CMD

done

 

使用ping命令测试信号捕捉:

  1 #!/bin/bash

  2 #

  3 NET=183.170.150

  4 FILEU=`mktemp /tmp/file.XX`

  5 FILED=`mktemp /tmp/file.XXX`

  6 clear (){

  7         echo "quit..."

  8         rm -f $FILEU

  9         rm -f $FILED

 10         exit 1

 11 }

 12 trap 'clear' INT

 13 for I in {1..254};do

 14   if ping -c 1 -W 1 $NET.$I &> /dev/null;then

 15         echo "$NET.$I is up." | tee -a $FILEU #tee -a追加到文件而不是覆盖文件

 16   else

 17         echo "$NET.$I is down." | tee -a $FILED

 18   fi

 19 done

 

练习:写一个脚本

定义一个数组,数组元素为/var/log目录下所有以.log结尾的文件的名字;显示每个文件的行数

#!/bin/bash

#

declare -a files

files=(/var/log/*.log)

for i in `seq 0 $[${#files[*]}-1]`; do

    wc -l ${files[$i]}

done

 

例:生成10个随机数,升序排序

#!/bin/bash

for((i=0;i<10;i++))

do

    rand[$i]=$RANDOM

done

echo -e "Total=${#rand[@]}\n${rand[@]}\nBegin to sort:"

for((i=9;i>=1;i--))

do

        for((j=0;j

    do

    if [ ${rand[$j]} -gt ${rand[$[$j+1]]} ] ;then

        mid=${rand[$j]}

        rand[$j]=${rand[$[$j+1]]}

        rand[$[$j+1]]=$mid   

    fi

    done

done

echo ${rnd[@]}

 

打印九九乘法表:

  1 #!/bin/bash

  2 for ((i=1;i<10;i++));do

  3         for ((j=1;j<10;j++));do

  4                 if [ $i -ge $j ];then

  5                         let k=$i*$j

  6                         echo  -ne "$j*$i=$k\t"

  7                 fi

  8         done

  9         echo

 10 done

 

 

 

name=${name:-tom}    #如果name有值则将自己赋值给自己,否则将tom赋值给name

Bash脚本编程(原创)_第1张图片

你可能感兴趣的:(Bash脚本编程(原创))