下面是bash的相关内容,包括bash的颜色代码、bash的四类文件、bash中变量处理方式、数组变量、shell的过程式编程语言以及部分简单脚本例子。

一、bash的颜色显示规则(颜色代码)

bash的颜色代码,是ASCII编码对于颜色进行设置。颜色代码中,字符串\033:表示Ctrl。其中,关于颜色代码的各字符实现的功能如下:

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

  0m:关闭颜色属性的命令

  1m:对于显示的文本字符进行加粗

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

  5m:使文本字符闪烁

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

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

  30m-39m:设置文本字符的前景色,即显示什么颜色的字符,38m和39m暂时没有用到

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

示例:多个复合例子

# echo -e "\033[5;1;31;47mhello world\033[0m" 必须加-e选项,被解释;然后加[0m退出


二、bash的四类文件

一个完整的程序,一般包括四类文件:即二进制文件(可执行文件)、头文件库文件、帮助文件、配置文件。bash是一个接口程序,是命令行接口(CLI)的一种,所以也包括该四类。

shell有两种类型,即交互式登录的shell和非交互式登录的shell,具体解释如下:

   (1)、交互式登录的shell:直接通过某个终端输入账号和密码后登录打开的shell进程;使用su - USERNAME或su -l USERNAME执行切换登录打开的shell进程

   (2)、非交互式登录的shell:在图形界面下,通过菜单或右键菜单打开的终端的shell进程;使用su USERNAME执行切换登录打开的shell进程


在bash中,# file /bin/bash 用来查询文件,/usr/include/下有库文件,/usr/share/下有帮助文件,例:# ls /usr/share/man/man1

 bash有三类配置文件:(1)、profile类:为交互登录的shell进程实现功能初始化的配置文件;(2)、bashrc类:为非交互登录的shell进程实现功能启动配置的配置文件;(3)、logout类:为交互式登录的shell进程提供终止即清理类功能的配置文件

 1、profile类

 在RHET或Centos的操作系统中,通常情况下,一个配置文件的内容很多,格式复杂,我们会将其切换为多个片段,将切割出来的片段统一存放在“程序名称.d”的文件中,在这样的目录中所保存的片段文件,大多以统一的文件后缀名来命名。

  profile类分为全局和用户个人两种,具体解释如下:

    全局(profile类):对所有用户都生效的配置文件,有 /etc/profile 和 /etc/profile.d/*.sh

    用户个人(profile类):仅仅只是针对某个用户有效的配置文件,有 ~/.bash_profile

 profile类配置的文件有两个作用:即用于定义用户的环境变量;用于运行脚本或执行命令。

 2、bashrc类

  bashrc类也分为全局和用户个人两种,具体解释如下:

     全局(bashrc类):有 /etc/bashrc

     用户个人(bashrc类):有 ~/.bashrc

 bashrc类配置的文件有三个作用:即用于定义本地变量;用于定义命令的别名;定义umask

 注意:只有超级用户root才可以修改全局类的配置文件,而普通用户只能修改其家目录中的个人配置文件

 3、logout类


登录进程加载配置文件的顺序可以如下:

  交互式登录的shell进程,会按照顺序加载下列配置文件:/etc/profile--->/etc/profile.d/*.sh---->~/.bash_profile--->~/.bashrc----->/etc/bashrc

  非交互式登录的shell进程,会按照顺序加载下列配置文件: ~/.bashrc----->/etc/bashrc---->/etc/profile.d/*.sh


所有在命令行中执行的命令操作,只要没涉及到文件的修改的,一般都只是针对当前的shell生命周期有效;只要shell进程结束,所有的设置均失效。配置文件的作用如下:使得我们赖以生存的配置信息可以长期有效,只要不修改配置文件中的内容,每一次打开shell都会使曾经的配置生效。


让配置文件中的新定义的配置能够立即生效的方式有source命令和exec命令两种,具体解释如下:

  1、source命令:把shell的内容在当前命令中运行。具体命令如下两种:

     source /PATH/TO/SOME_CONF_FILES

     . /PATH/TO/SOME_CONF_FILES

  2、exec命令:使用指定命令来替换shell。具体命令如下:

     exec /PATH/TO/SOME_CONF_FILES


 

 三、bash中变量处理方式

 变量是内存中的一段存储空间。其中的弱变量,无需事先定义即可使用;没有变量数据类型的硬性要求,默认是字符型。

 bash中变量存放的7种字符串内容处理方式如下(处理时其值没有变,而只是执行时改变):

  1、字符串切片

    ${#VAR}:返回字符串类型的变量VAR的长度

    ${VAR:offset}:返回字符串变量VAR中第offset个字符后面的内容,不包括offset这个字符,offset的取值范围为:0-$[$(#VAR)-1]

    ${VAR:offset:number}:返回字符串变量VAR中第offset个字符后开始,长度为numer的字符部分

    ${VAR: -length}:取字符串最右侧的length个字符,从右向左选择

  2、基于模式取字串

    ${VAR#*PATTERN}:自左而右,查找VAR变量所存储的字符串中,第一次被PATTERN匹配的字符,删除从字符串开始到PATTERN匹配的字符之间的所有字符(可以取基名)-----留后面

    ${VAR##*PATTERN}:自左而右,查找VAR变量所存储的字符串中,所有被PATTERN匹配的字符,删除从字符串开始到最后一个PATTERN匹配的字符 

    ${VAR%PATTERN*}:自右而左,查找VAR变量所存储的字符串中,第一次被PATTERN匹配的字符,删除从字符串开始到PATTERN匹配的字符之间的所有字符(可以取目录名)------留前面

    ${VAR%%PATTERN*}:自右而左,查找VAR变量所存储的字符串中,所有被PATTERN匹配的字符,删除从字符串开始到最后一个PATTERN匹配的字符之间的所有字符

  3、查找替换

    ${VAR/PATTERN/SUBSTRING}:在VAR变量中查找匹配PATTERN的内容,将其第一个匹配到的结果更换成SUBSTRING

    ${VAR//PATTERN/SUBSTRING}:在VAR变量中查找匹配PATTERN的内容,将其所有匹配到的结果更换成SUBSTRING

    ${VAR/#PATTERN/SUBSTRING}:在VAR变量中查找 行首 匹配PATTERN的内容,将匹配到的结果更换成SUBSTRING

    ${VAR/%PATTERN/SUBSTRING}:在VAR变量中查找 行尾 匹配PATTERN的内容,将匹配到的结果更换成SUBSTRING

  4、查找删除

    ${VAR/PATTERN}:在VAR变量中查找匹配PATTERN的内容,将其第一个匹配到的结果删除

    ${VAR//PATTERN}:在VAR变量中查找匹配PATTERN的内容,将其匹配到的结果删除

    ${VAR/#PATTERN}:在VAR变量中查找匹配PATTERN的内容,将其 行首 匹配到的结果删除

    ${VAR/%PATTERN}:在VAR变量中查找匹配PATTERN的内容,将其 行尾 匹配到的结果删除

  5、字符的大小写转换

    ${VAR^^}:将VAR变量中的所有小写字母转换为大写字母

    ${VAR,,}:将VAR变量中的所有大写字母转换为小 写字母

  6、变量赋值

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

    ${VAR:+value}:如果变量不为空,那么直接返回变量VAR的值,否则返回value值

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

  7、变量的间接引用

    如果第一个变量的值是第二个变量的变量名,从第一个变量引用第二个变量的值的方法,就称为变量的间接引用,也称为间接变量引用。例如:VAR1=VAR2 VAR2=value

    bash提供的两种格式的间接变量的引用方式:(1)、eval MYVAR=\$$VAR1 相当于 MYVAR=value ; (2)、MYVAR=${!VAR1}


四、数组变量

 变量为内存中的存储空间。变量的特点为,每个变量中只能存放一个数据,即变量只能进行一次性的赋值,否则被覆盖。

 示例:存放本班每个人的名字于变量,三种赋值方式如下:

  (1)、一次性赋值:ANME="name1 name2 name3……"

  (2)、使用多个变量分别赋值:NAME1=little1 NAME2=little2 NAME3=little3 ……

  (3)、使用数组变量

1、数组的组成部分

 数组变量:相似属性的数据组,存放一个或多个元素的连续内存空间(当然也可以有空数组),相当于多个变量的集合。

 数组元素:数组中任何一个存放数据的存储单元

 数组的索引包括两部分:

  (1)、数字:索引数组(index array)例 0,1,2,3,4,5,…… 

  (2)、名称(字符串):关联数组(related array) ; 但是只有bash4.0以上的版本才支持关联数组

2、数组的分类

 数组分为稠密数组和稀疏数组。稠密数组,其索引编号必须连续;稀疏数组,其索引编号可以不连续,bash数组属于此类稀疏数组。

3、声明数组

  (1)、declare命令 

   declare -i NAME:将NAME声明为×××变量

   declare -x NAME:将NAME声明为环境变量

   declare -a NAME:将NAME声明为索引数组(版本支持时可以用)

   declare -A NAME:将NAME声明为关联数组(版本支持时可以用)

   示例:declare -a NAME=("value1" "value2" "value3" ……)

         declare -a NAME=([0]="value1" [1]="value2" [6]="value3" ……) 

  (2)、直接声明数组

    ARRAY_NAME=("value1" "value2" "value3" ……)  即声明稠密数组——直接为数组赋值

    ARRAY_NAME=([0]="value1" [1]="value2" [6]="value3" ……)  即声明稀疏数组

  (3)、定义数组的元素而创建的数组

    ARRAY_NAME[0]=value1   

    ARRAY_NAME[1]=value2 

    ……  

4、引用数组中的元素:

  引用变量的方法:${NAME}

  引用数组元素的方法:${ARRAY_NAME[INDEX]} 

    注意:如果不给出INDEX,则表示引用数组的第一个元素,即INDEX=0的元素

  引用整个数组的所有元素的索引号:${!ARRAY_NAME[*]}或者${!ARRAY_NAME[@]} 

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


5、查找数组的长度(数组中有效元素的个数)

  ${#ARRAY_NAME[*]} 

  ${#ARRAY_NAME[@]} 

6、数组切片

  ${ARRAY_NAME:offset}:显示包括offset  例:${ARRAY_NAME:6}:跳过0-5,从6开始,跳过了6个

  ${ARRAY_NAME:offset:number}:显示包括offset数组所代表的索引位置及以后的number个元素  

  示例:${ARRAY_NAME:6:3}:跳过0-5,从6开始,显示6、7、8,其中跳过了6个。

7、向数组中追加元素:

  稠密数组追加:ARRAY_NAME[${#ARRAY_NAME[*]}]=valueN

  稀疏数组追加:ARRAY_NAME[INDEX]=valueN 注意:稀疏数组追加的INDEX必须为未被使用的数组元素的索引编号

8、撤销数组:usnet ARRAY_NAME

9、删除数组中的元素:usnet ARRAY_NAME[INDEX]

  RANDOM变量:随机数变量,0-32767(2^15-1)


五、bash脚本编程

示例1、写一个脚本:创建一个用户little,如果用户已经存在,就提示用户已经存在的信息,否则将创建用户

# id little &> /dev/null && echo 存在 || useradd little


1、shell脚本编程的特点:过程式编程语言、脚本类语言、解释型语言。

 过程式编程语言包括3种基本结构,顺秀执行结构、选择执行结构和循环执行结构,具体解释如下:

 顺秀执行结构:以从左到右,从上到下顺序执行所有语句(命令),顺序执行结构是shell脚本的主体结构

 选择执行结构:依照给定条件的逻辑判断结果依照可选的取值范围,进而选择某个分支中的语句来执行。具体有if和case两种分支结构,即if的分支选择标准,是逻辑判断的结果;case的分支选择标准,是根据可选的取值。

 循环执行结构:对于某特定语句,重复执行n次。具体有for、while、until、select,解释如下:

   for:遍历指定的列表,列表必须事先存在,大规模不建议使用

   while:根据逻辑判断的结果判断是否进入循环

   until:根据逻辑判断的结果判断是否进入循环

   select:永远的死循环,不给命令退出就一直执行

 

 2、选择执行结构:

  if语句:if是shell的关键字,不允许有别名

  格式:if 命令; then 命令;[elif 命令; then 命令]……[else 命令;] fi 

  if语句的2种单分支结构表达格式如下:

  if CONDITION

  then statement

  fi


  if CONDITION;then 

  statement1

  statement2

  ……

  fi

    注意:想要执行then后面的statements,前提条件是CONDITION部分为真

  if语句的双分支结构:如果条件为真,就执行then后面的命令;否则就执行else后面的命令

    if CONDITION;then

       statement

       ……

    else

       statement

       ……

    fi

  if语句的多分支结构:首先判断CCONDITION1是否为真,如果为真,则执行第一个then后面的语句;否则判断CONDITION2是否为真,如果为真,则执行第2个then后面的语句……

    if CONDITION1;then

       statement

       ……

    elif CONDITION2;then

       statement

       ……

    elif CONDITION3;then

       statement

       ……

    fi

 示例2:写一个脚本,列出系统中默认shell的bash用户

 #!/bin/bash

 #

 if grep -q "bash$";then

    grep  "bash$" | cut -d: -f1

 fi 


3、bash脚本之间的用户交互

 bash脚本的位置参数变量为:$1、$2、$3、……

 bash脚本的特殊变量为:

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

   $* :给出的所有位置参数的列表,当使用双引号引用时,整个参数列表被当做一个字符串

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

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

示例3:创建一个用户,如果用户已经存在,就提示用户已经存在的信息,否则将创建用户

#!/bin/bash

#

if id $1 &> /dev/null;then

  echo "$1 存在"

else

  useradd $1

fi


示例4:写一个脚本,给脚本传递用户名参数,判断参数数量是否合格,并且判断用户是否存在,如果存在,就显示相应信息,否则就创建之并为其设置密码

#!/bin/bash

#

if [ $# -ne 1 ];then

  echo "Only ONE USERNAME can be spacified."

  exit 5

fi


if id $1 &> /dev/null ; then

  echo "$1 exists already."

else 

  useradd $1

  echo $1 | passwd --stdin $1 &> /dev/null

  echo "create $1 successfully."

fi



4、read命令:read是bash的内置命令

  格式:read [-a 数组] [-p 提示符] [-t 超时]  [名称 ……]  

  read格式中的[名称]:一般为变量名或者数组名,如果不写名称,则系统会将read读到的信息保存在REPLY变量中

示例5:# read -p "Please enter some username: " NAME1 NAME2 NAME3 回车后输出:Please enter some username: little1 little2 little3

 注意:read可以使用户与shell进行交互,在使用read命令的时候,通常会使用-t选项规定超时时间,一旦使用-t选项定义了超时时间,我们必须在后面判断给定的变量是否为空,如果为空则需要为变量名提供默认值

示例6:写一个脚本,能够添加或删除用户账户,可以使用-a选项完成添加,使用-d选项完成删除任务

#!/bin/bash

#

if [ $# -ne 2 ] ; then 

  echo "usage: $(basename $0) -a useranme | -d username."

  exit 5

fi


if [ $1 == '-a' ] ; then 

  if id $2 &> /dev/null ; then 

     echo "$2 exits already."

  else 

     useradd $2

     echo $2 | passwd --stdin $2 &> /dev/null

     echo "create $2 successfully."

  fi

fi


if [ $1 == '-d' ] ; then 

  if id $2 &> /dev/null ; then

    userdel -r $2

    echo "delete $2 finished."

  else

    echo "user $2 does not exit."

  fi

fi


示例7:判断给出的文件大小是否大于100kb,如果大于100kb,就显示这是个大文件,否则就显示这是一个小文件

#!/bin/bash 

#

filesize=$(wc -c < $1)

if [ $filesize -gt 102400 ] ; then

  echo "Big file."

else 

  echo "Small file."

fi


示例8:判断给出的一个字符串是否为整数

#!/bin/bash

#

if echo $1 | grep "^\<[[:digit:]]\+\>$" &> /dev/null ; then 

   echo "$1 is integer."

else

   echo "$1 is not integer."

fi


5、shift命令(完成位置参数的迁移)

 shift的格式:shift [n] 

示例9:示例6的扩展,用shift实现:写一个脚本,能够添加或删除用户账户,可以使用-a选项完成添加,使用-d选项完成删除任务

#!/bin/bash

#

if [ $# -ne 2 ] ; then 

  echo "usage: $(basename $0) -a useranme | -d username."

  exit 5

fi


if [ $1 == '-a' ] ; then 

  shift

  if id $1 &> /dev/null ; then 

     echo "$1 exits already."

  else 

     useradd $1

     echo $1 | passwd --stdin $1 &> /dev/null

     echo "create $1 successfully."

  fi

fi


if [ $1 == '-d' ] ; then 

  shift

  if id $1 &> /dev/null ; then

    userdel -r $1

    echo "delete $1 finished."

  else

    echo "user $1 does not exit."

  fi

fi



示例10:简易计算器

#!/bin/bash

#

echo $[$1$2$3]

引用:# ./little.sh 3 + 5  输出8 (3个输入)


6、if语句的多分支结构:

if CONDITION1;then

       statement

       ……

    elif CONDITION2;then

       statement

       ……

    elif CONDITION3;then

       statement

       ……

    else

       statement

       ……

    fi

示例11:编写一个脚本,要求:从/etc/passwd中UID和GID相同的用户中随机选择一个用户,判断其用户的类型:UID为0,即超级用户;UID在1-999之间,即系统用户;UID为1000+,即登录用户。

#!/bin/bash

#

LINES=$(egrep "\<([[:digit:]]+)\>.*\1" /etc/passwd | wc -l)

SEQUENCE=$[${RANDOM}%${LINES}+1] 

USERNAME=$(egrep "\<([[:digit:]]+)\>.*\1" /etc/passwd | head -n $SEQUENCE | tail -1 | cut -d: -f3)


if [ $USERID -eq 0 ] ; then

  echo "$USERNAME is super user."

elif [ $USERID -ge 1000 ] ; then

  echo "$USERNAME is login user."

else 

  echo "$USERNAME is system user."

fi


7、循环执行结构

 循环执行结构,就是将一段代码循环的执行0次、1次或多次。一个好的循环结构,必须包含两个重要的环节,进入循环的条件和退出循环的条件;进入循环的条件,即开始循环时所满足的条件;退出循环的条件,即循环结束所满足的条件

 (1)、for循环:

  for循环的遍历列表格式:

  for VAR_NAME in LIST ; do 循环体; done

  for VAR_NAME in LIST ; do 

      循环体;

  done

  for格式中的各个解释如下:

  VAR_NAME :任意指定的变量名称,变量的值是从LIST中取值并赋值的

  循环体:能够用到VAR_NAME的命令或目录的组合;如果循环体中,没有包括变量内容VAR_NAME,则可能出现死循环

  LIST的生成方式很多,具体如下:

   1)直接给出;

   2)纯整数列表:seq:输出一个纯整数列表  seq [FIRST [INCREMENT]] LAST 例:sqe 1 2 10(输出奇数,2表示增量)

   3)花括号展开:{FIRST..LAST} 例如:echo {1..100} ; echo {a..z} ; echo {A..Z}

   4)命令的执行结果的返回值

   5)GLOBBING

   6)某些变量的引用: $@  $*

示例12:写一个脚本,能够添加或删除一个或多个用户账户,可以使用-a选项完成添加,使用-d选项完成删除任务

#!/bin/bash

#

if [ $# -lt 2 ] ; then

  echo "Usage: $(basename $0) -a User1 User2 ... | -d User1 User2 ..."

  exit 5

fi


if [ $1 == '-a' ] ; then

  shift

  for I in $* ; do

    if id $I &> /dev/null ; then

      echo "$I exists already."

    else

      useradd $I

      echo $I | passwd --stdin $I &> /dev/null

      echo "Create $I successfully."

    fi

  done

fi


if [ $1 == '-d' ] ; then

  shift

  for J in $* ; do

    if id $J &> /dev/null ; then

      userdel -r $J

      echo "Delte $J finished."

    else

      echo "User $J does not exist."

    fi

    done

fi


8、for循环的优势及特点

  for循环:进入循环条件,LIST中有元素可以取用;退出循环条件,LIST中被取空,再无元素可用

  for循环的特点:1、几乎不会出现死循环;2、在执行循环的过程中,需要将这个LIST载入内存,因此,对于大列表来说,可能会过多的消耗内存和CPU资源

  注意:使用for循环嵌套的时候,外层for循环,控制行数的输出;内层for循环,控制列数的输出

示例13:计算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


for I in $(seq $INTEGER) ; do

# let SUM+=$I

# let SUM=$SUM+$I

  SUM=$[SUM+I]

done

echo $SUM

100以内的也可以为:for I in {1..100} ; do for I in {seq $1} ; done


示例14:写一个脚本,打印倒置的等腰三角形。每行星星个数公式:2*[n-($n-1)]-1 ; 2*(总行数-第几行)+1

*********   1  0  9   行-1个空格 以及 2*(总行数-行)+1 个星星 

 ******* 2  1  7

  ***** 3  2  5

   *** 4  3  3

    * 5  4  1

#!/bin/bash

#

LINENUM=$1

for I in $(seq $LINENUM) ; do

  for J in $(seq $[I-1]) ; do

    echo -n " "

  done

  for K in $(seq $[2*(LINENUM-I)+1]) ; do

    echo -n "*"

  done

  echo

done   


示例15:打印九九乘法表

#!/bin/bash

#

for I in {1..9} ; do

  for J in $(seq $I) ; do

    echo -ne "$I*$J=$[I*J]\t"

  done

  echo

done


1X1=1 1X2=2 1X3=3 ... 1X9=9

2X2=4 2X3=6 ... 2X9=18

...

9X9=81


 2、控制变量

 for ((表达式1; 表达式2; 表达式3)); do 命令; done

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

   循环体

 done

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

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

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

示例16:# for ((I=1; I<=100; I++)); do let SUM+=$I; done

#!/bin/bash

for (( I=1; I<=100; I++ )); do

let SUM+=$I

done

echo $SUM