首页 > 代码库 > bash颜色、变量、数组、相关脚本示例
bash颜色、变量、数组、相关脚本示例
下面是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
bash颜色、变量、数组、相关脚本示例