今天给大家总结一下关于bash的颜色,配置文件,变量,数组和相关shell脚本编程的基本概念;

  一.bash的颜色显示规则

  吧是的颜色显示,说白了就是Ascll码对于颜色的调用设置,而在于颜色代码当中,字符串个功能实现如下:

  \033:表示ctrl键;

  [:控制字符和颜色代码之间的间隔字符;

  0m:关闭颜色属性;

  1m:加粗显示文本字符;

  4m:为文本字符加下划线标识;

  5m:使文本字符闪烁;

  7m:将背景色和前景色调换,白变黑,黑变白;

  8m:隐藏字符,将文本字符的背景色和前景色设置为相同颜色,同为黑或同为白;


  30m-39m设置文本字符的前景色,即字体颜色,38m和39m暂时没有用到;

  40m-49m:设置文本字符的背景色,即一个黑色字符的背景后是什么颜色,48m和49m暂时没有用到;

  前景   背景    颜色  

   30m    40m    黑色

   31m    41m    红色

   32m    42m    绿色

   33m    43m    ×××

   34m    44m    蓝色

   35m    45m    紫红色

   36m    46m    青蓝色

   37m    47m    白色

  加粗显示文本字符

  [root@localhost wjq]# echo -e "\033[1mhello worl\033[0m"

  hello worl

  

  为文本字符加下划线标识

  [root@localhost wjq]# echo -e "\033[4mhello worl\033[0m"

  hello worl

  

  加粗和设置下划线同时进行,利用“;”分隔;

  [root@localhost wjq]# echo -e "\033[1;4mhello worl\033[0m"

  hello worl


  二.配置文件

  一个完整的程序通常包含四类文件:

  二进制文件:可执行文件;

  头文件,库文件;

  帮助文档;

  配置文件;

  所有在命令行进行命令的操作,只要没有设计到文件的修改都只是在当前生命周期有效的,当关闭系统后,再开启则无法使用;配置文件是实现数据永久显示的基本方法,将数据的改动放入配置文件中,当系统重启后还能重复调用,如修改alias别名放入配置文件bashrc的文本文档当中,bashrc就是一个配置文件;

  配置文件分为私人配置文件与通用配置文件

  通用配置文件:/etc/bashrc,/etc/profile

  私人配置文件:~/.bashrc,~/.bash_profile

          

  注意:一般情况下定义变量都是先做先用,并不需要改配置文件(声明变量在配置文件中可能使系统出现漏洞)没有必要就不要改;

  配置文件又分为三类:

  profile类:

  为交互式登陆的shell进程实现功能初始化的配置文件;

  bashrc类:

  为非交互式登陆的shell进程实现功能启动配置的配置文件;

  logout类:

  为交互式登陆的shell进程提供终止及清理类功能的配置文件;


  交互式登录:

  1.通过某个终端输入账号密码来打开的shell进程;

  2.通过su - username打开的shell进程;

  非交互式登陆:

  1.在图形界面,通过右键菜单打开终端的shell进程;

  2.通过su username打开的shell进程;


  profile类:

  /etc/profile

  /etc/profile.d/*.sh

  全局:在上述路径中对配置文件进行修改,能对所有登陆的用户进行改变;

  往往在profile文件中,如果一个配置文件中的内容过多,系统会把其切割成一个个片段,如profile.d,将切割出来的片段统

  一的存放在”程序名称.d“目录,在该目录下有关于片段的所有文件大多以统一的文件名后缀来命名;

  

  ~/.bash_profile

  局部:仅针对当前家目录的用户,对其进行改变,不影响其他用户;


 bashrc类:

 /etc/bashrc

 全局:可以定义对系统全部用户有效的命令别名,本地变量,以及遮罩码umask;

 ~/.bashrc

 局部:定义对于当前用户有效的命令别名,本地变量,以及遮罩码umask;


 三.变量应用

 1.字符串切片

 ${#var:}:返回变量var的字符串长度;

 ${var:offset}:返回字符串变量var的第offset个字符后面的字符串;

 ${var:offset:number}:返回字符串变量var的第offset个字符后面的number个字符;

 例

 [root@localhost wjq]# var="hello world"

 [root@localhost wjq]# echo ${#var}

 11

 返回第六个字符后的字符串

 [root@localhost wjq]# echo ${var:6}

 world

 返回第六个字符后的两个字符串

 [root@localhost wjq]# echo ${var:6:2}

 wo

 

 2.基于模式取字串:根据不同方式取符合pattern的字符串

 ${var#*pattern}:在var字符串变量中,从左到右搜索第一个匹配字符串pattern的字符,删除从开始到第一个匹配到pattern的所有字符;


 ${var##*pattern}:在var字符串变量中,从左到右搜索最后一个匹配字符串pattern的字符,删除从开始到最后一个匹配到pattern的所有字符;


 ${var%pattern*}:在var字符串变量中,从右到左搜索第一个匹配到pattern的字符,删除从开始到从右到左匹配的第一个pattern之间的所有字符;


 ${var%%pattern*}:在var字符串变量中,从右到左搜索最后一个匹配到pattern的字符,删除从开始到从右到左最后一个匹配到的字符之间的所有字符;

 

 例

 ①

 [root@localhost wjq]# var=/etc/passwd

 [root@localhost wjq]# echo ${var#*p}

 asswd

 ②

 [wjq@localhost ~]$ var=/etc/passwd

 [wjq@localhost ~]$ echo "${var##*/}"

 passwd

 ③

 [wjq@localhost ~]$ var=/etc/passwd

 [wjq@localhost ~]$ echo "${var%s*}"

 /etc/pas

 [wjq@localhost ~]$ 

 ④

 [wjq@localhost ~]$ var=/etc/passwd

 [wjq@localhost ~]$ echo "${var%%s*}"

 /etc/pa

 [wjq@localhost ~]$ 


 3.查找替换:利用不同方式,搜索字符串中匹配pattern的字符,并用substring字符串对其进行替换;

 ${var/pattern/substring}:在var字符串变量中,搜索第一个匹配到pattern的字符串,并用substring字符串对其进行替换;


 ${var//pattern/substring}:在var字符串变量中,搜索所有匹配到字符串pattern的字符串,并用substring字符串进行替换;


 ${var/#pattern/substring}:在var字符串变量中,搜索行首匹配到字符串pattern的字符串,并用substring字符串进行替换;


 ${var/%pattern/substring}:在var字符串变量中,搜索行尾匹配到字符串pattern的字符串,并用substring字符串进行替换;


 例

 ①

 [wjq@localhost ~]$ var=/etc/passwd

 [wjq@localhost ~]$ echo "${var/e/wu}"

 /wutc/passwd

 ②

 [wjq@localhost ~]$ var=/etc/passwd

 [wjq@localhost ~]$ echo "${var//s/wu}"

 /etc/pawuwuwd

 ③

 [wjq@localhost ~]$ var=/etc/passwd

 [wjq@localhost ~]$ echo "${var/#\//wu}"

 wuetc/passwd

 ④

 [wjq@localhost ~]$ var=/etc/passwd

 [wjq@localhost ~]$ echo "${var/%d/wu}"

 /etc/passwwu


 4.查找删除:利用不同方式,搜索匹配到的字符串并删除;

 ${var/pattern}:在字符串变量var中,将第一次匹配到pattern的字符串删除;


 ${var//pattern}:在字符串变量var中,将全部匹配到pattern的字符串删除;


 ${var/#pattern}:在字符串变量var中,将行首匹配到pattern的字符串删除;

 

 ${var/%pattern}:在字符串变量var中,将行尾匹配到pattern的字符串删除;


 例

 ①

 [wjq@localhost ~]$ var=/etc/passwd

 [wjq@localhost ~]$ echo "${var/p}"

 /etc/asswd

 ②

 [wjq@localhost ~]$ var=/etc/passwd

 [wjq@localhost ~]$ echo "${var//s}"

 /etc/pawd

 ③

 [wjq@localhost ~]$ echo "${var/#\/}"

 etc/passwd

 ④

 [wjq@localhost ~]$ echo "${var/%wd}"

 /etc/pass


 5.字符的大小写转换:

 ${var^^}:将字符串var变量中的所有小写字母转换成大写字母;

 ${var,,}:将字符串var变量中的所有大写字母转换成小写字母;


 例

 ①

 [wjq@localhost ~]$ var=/etc/passwd

 [wjq@localhost ~]$ echo "${var^^}"

 /ETC/PASSWD

 [wjq@localhost ~]$ 



 6.变量赋值:

 ${var:-value}:如果变量var为空或未被设置,那么直接返回value值,否则返回变量var值;


 ${var:+value}:如果变量var不为空,则返回value,为空则返回var;


 ${var:=value}:如果变量var为空或者未被设置,那么直接返回value值,并且将value值赋值给变量var,否则返回var值;


 例

 ①

 [wjq@localhost ~]$ var=//

 [wjq@localhost ~]$ echo "${var:-qq}"

 //

 [wjq@localhost ~]$ var=

 [wjq@localhost ~]$ echo "${var:-qq}"

 qq


 ②

 [wjq@localhost ~]$ var=

 [wjq@localhost ~]$ echo "${var:+qq}"

 [wjq@localhost ~]$ var=a

 [wjq@localhost ~]$ echo "${var:+qq}"

 qq


 7.变量的间接引用:

 如果第一个变量的值恰好是第二个变量的变量名,从第一个变量引用第二个变量的值的方法,就称为间接变量引用;

 var1=var2

 var2=value

 bash提供了两种格式的间接变量引用方式:

 eval myvar=\$$var1==>\$var2

 myvar=$(!var1)


 四.数组

 数组:相当于几个变量的集合,存放着一个或多个内存空间;

 在bash中只提供一维数组,并且没有限定数组大小,利用下标存取数组中的元素,数组元素由下标0开始编号即数组的索引结点:0,1,2...,数组可以采用连续的索引结点进行赋值——稠密数组,也可以采用不连续的索引结点进行赋值——稀疏数组。

 数组名[下标]=值

 例如:

 $a[0]=beijing

 $a[1]=hainan

 $a[2]=shanghai


 数组的声明:

 1.数组可以采用上述声明方式逐个赋值

 2.直接对数组元素进行赋值:

 $a=("beijing" "shanghai" "tianjin")或者$a=([0]="beijing" [1]="shanghai" [3]="tianjin")

 3.利用declare命令创建数组:

 $declare -a 数组名

 

 引用数组元素:

 1.$name或${name},两者相同,若变量未定义则用空值替换;

 2.引用固定的数组元素:${name[n]}引用索引结点为n的值;

 3.引用整个数组的所有元素:${name[*]}或${name[@]}


 例

 [wjq@localhost ~]$ a[0]=beijing

 [wjq@localhost ~]$ echo "${a[0]}"

 beijing


 [wjq@localhost ~]$ a=("wujunqi zhengzhong shaoning")

 [wjq@localhost ~]$ echo "${a[0]} ${a[1]} ${a[2]}"

 wujunqi zhengzhong shaoning 


 查看数组的长度:

 可以通过${#name[*]}显示出这个数组有多少个有意义的元素;

 例

 [wjq@localhost ~]$ a=(wujunqi zhengzhong shaoning)

 [wjq@localhost ~]$ echo "${#a[*]}"

 3


 数组切片:

 ${name:offset}:显示包括offset数字所表示的索引位置及以后的所有元素,去掉从第一个数组开始的offset个数组元素

 ${name:offset:number}:显示包括offset数字所表示的索引位置及包括offset个元素的number个元素;

 如${name:3:2}:丢弃0-2的数组变量,只取3,4数组变量;

 

 撤销数组:

 unset array_name


 删除数组中的元素:

 unset array_name[index]


 RANDOM变量:可以产生一组在0-32767之间的随机变量

 例

 [wjq@localhost ~]$ echo "$RANDOM"

 16952

 [wjq@localhost ~]$ echo "$RANDOM"

 6653

 

 五.bash脚本编程

 shell脚本编程有三种:

 过程式编程语言

 脚本类编程语言

 解释性语言

 其中脚本类编程语言在实现功能时是通过调用外部文件来实现的;

 

 过程式编程语言有三种结构,顺序执行结构,选择执行结构和循环分支结构;

 1.顺序执行结构:

 根据用户所写的脚本命令,从左至右,从上到下按顺序执行;

 

 2.选择执行结构:

 对于某特定语句,重复执行0次,一次或多次;如if,case语句;

 if语句:

 单分支语句:

 if 测试条件

 then 命令

 fi


 双分支语句:

 if 测试条件

 then 命令1

 else 命令2

 fi


 多分支语句:

 if 测试条件

 then 命令1

 elif 测试条件

 then 命令2

 。。。

 fi

 

 例

 计算100以内所有整数的和;

 #!/bin/bash

 #

 read -t 5 -p "Please input a integer[0]: " INTEGER

 if [ -z $INTEGER ] ; then

 INTEGER=0

 fi

 if ! echo $INTEGER | grep -q "^\<[[:digit:]]\+\>$" ; then

 echo "You must input an integer."

 exit 5

 fi


 case语句:

 可以进行多重条件选择,相对于if,else的多分支语句,case语句的优势就在于节约了系统所消耗的资源,其语法格式为:

 case 变量引用 in

    模式1)

      分支1

      ;;

    模式2)

      分支2

      ;;

      ...

      *)

    默认分支

    ;;

  esac

 其执行过程是,利用变量引用所代表的值分别与各类模式进行比较,如果发现变量引用的值与某一类模式相同时,就执行该模式字符串之后的各个命令,直到遇到两个分号结束为止;

 case语句的模式可以匹配数字,字符串,通配符等模式;

 注意:

 ①每个模式字符串后面可有一条或多条命令,最后一条命令必须要由“;;”隔开

 ②模式字符串可以使用通配符;

 ③如果一个模式字符串包含多个模式,则应用“|”隔开;

 ④各模式字符串应唯一;

 ⑤以关键字esac结束;


 3.循环分支结构

 将一段代码重复的执行0次,1次或多次;一个好的循环结构必须要包括两个最重要的环节,即进入循环的条件:开始循环时所满足的条件;

 退出循环的条件:

 循环结束所满足的条件;

 shell中有三种用于循环的语句,即for,whie,until,select语句;

 for语句:

 for语句是最常用的循环结构语句。其使用方式主要有两种,一种是值表方式,另一种是算术表达式方式;for循环特点,几乎不会死循环,在执行循环的过程中,需要将这个LIST载入到内存当中;因此对于大列表来说可能会过多的消耗内存和cpu资源;

 值表方式

 其一般表达式为

 for 变量 [in 值表];do 命令表;done

 ①值表可以是文件正则表达式,其格式为:

 for 变量 in 文件正则表达式

 do

   命令表

 done

 其执行过程是,变量的值依次取当前目录下与正则表达式相匹配的文件名,每取值一次,就进入循环体执行命令表,直至所有文件名取完为止;

  

 bash脚本编程之用户交互:

 位置参数变量:$1,$2,$3,...

 特殊变量:

  $#:所有位置参数的总数;

  $*:所有位置参数列表;当使用“”引用时,整个参数被当作一个字符串;

  $@:所有位置参数列表;当使用“”引用时,每个参数作为单独的字符串存在;

  $0:所执行脚本文件自身的路径;

 

 ②for循环脚本也可以是全部的位置参数$#与$*

 for 变量 in $*

 do

   命令

 done

 

 ③

 for循环脚本可以直接使用纯整数列表

 {1..100}:表明从1-100,中间只能为两点;

 for i in {1..100}

 do

   命令

 done


 seq:输出一个整数列表

 seq [OPTION]... FIRST INCREMENT LAST

 seq 10:从1-10

 seq 5 10:从5-10

 for i in $(seq 10)

 do

   命令

 done

 

 在这里扩充一下关于read命令的功能

 read 命令:从键盘上读取数据,然后赋给指定变量;

 read [-a 数组] [-p 提示符] [-t 超时] []

 利用read命令可交互的为变量赋值,输入数据时,数据间以空格或制表符作为分隔符;

 ①

 变量个数与给定数据个数相同,则依次赋值

 $read x y z

 $today is sunny

 $echo $x $y $z

 today is sunny

 ②

 变量个数少于数据个数,则从左至右赋值,但最后一个变量被赋予剩余的所有数;

 ③

 变量个数多于数据个数,则依次对应赋值,而没有数据与之对应的变量取空串;

 例

 在脚本中-p选项给提示信息,相当于echo

 $read -p "please enter" name

 

 -t选项5秒钟内如果没有进行输入则返回,默认名字为link;

 $read -t 5 -p "please enter[link]" name || [ -z $name] && name=link

  

 算术表达式方式:

 其一般格式为

 for((表达式1; 表达式2; 表达式3 ))

 do

   命令表

 done

 表达式1:为变量赋初值;

 表达式2:循环退出条件;

 表达式3:变量值的变化规律;

 如

 for((T=1;I<=100;I++));do let "sum+=I";done;echo $sum


 while语句:

 格式:

 ①while 命令;do 命令;done

 ②while CONDITION;do

   循环体

   done

   当CONDITION为真时,进入执行循环体中的语句,直至CONDITION为假时,跳出循环;

   例当位置参数$1存在时执行while循环

   while [ $1 ]

   do

    if [ -f $1 ]

    then

      echo "该文件为普通文本文件"

    else

      echo "$1 is not a file"

    fi

   done


 until语句:

 格式:

 ①until 命令;do 命令;done

 ②until CONDITION;do

    循环体

  done

  当CONDITION为假时,进入执行循环体中的语句,直至CONDITION为真时,跳出循环;


 循环控制命令:

 continue语句:

 跳出当前循环语句,回到本层循环的开头,进入下一轮条件判断,若符合条件则进入下一轮循环;

 若处在多层嵌套循环中,如:

 for

   while 

      for 

        continue [3]

 跳出到最外层的循环,进行最外层循环的下一轮条件判断,若符合则继续循环;

 例如:

 for i in 1 2 3

 do

   if [ $i -eq 2 ]

   then

      continue

   fi

   echo "$i"

 done


 break语句:

 break语句可以使脚本从循环体中退出来,同continue相似,语法格式为:

 break [n]

 n默认值为1,即跳出一层循环;

 若n=3时,表示连续跳出三层循环;

 例如

 for i in $*

 do

   if [ $i -eq 5 ]

   then

       break

   else

       echo "$i"

   fi

 done

 当位置参数等于5时退出当前循环;


函数:

 由某些功能封装在一起,在需要的时候可以直接调用,将这种封装起来的功能体称作为函数;

 函数与shell程序在形式上是一致的,但是,shell程序是可以直接执行的,但函数中的语句是要通过函数调用过后才能被执行;此外,函数中的命令是在当前shell的环境中运行,而shell程序中的命令是在子shell环境中运行;

 函数应先定义之后才能被执行,可以像普通命令一样直接使用,直接利用函数名,如show,不必带圆括号即可调用;shell脚本与函数之间可以进行参数传递,函数中的$1,$2所对应的值是函数在调用时所带的实参,还可以使用$*或$@的方式引用所有位置参数;还可以使用$#计算为函数传递的参数个数;这一点与普通命令不同;函数的生命周期是从被调用开始直到遇到return结束命令或全部的命令语句执行完为止;

 如

 show arg1 arg2

 arg1和arg2作为函数的实参;


 函数定义格式:

 语法一:

 函数名()

 {

 命令表

 }

 语法二:

 function 函数名()

 {

  命令表

 }

 

 使用set命令可以查看所有当前shell中生效的函数;

 使用unset命令可以撤销已经定义的函数;

 

 调用函数之后函数的返回值有两种:

 ①函数结果的返回值

 如echo,print等输出结果;

 ②函数状态返回值;

 return [0];

 函数的返回值不能用exit命令,n为退出函数时的退出值,即$?的值,n值默认时,则退出值是最后一个命令执行后的返回值;