3.2. 2 字符串与数组

3.2.1. 1 字符串常用操作

1.1 获取字符串长度

方式1 利用${#var}来获取字符串长度

[root@xuel-tmp-shell ~]# var='abcstring'
[root@xuel-tmp-shell ~]# echo ${#var}
9

方式2

# $string上的双引号必不可少
expr length "$string"

1.2 字符串切片

格式:

·${parameter:offset}

·${parameter:offset:length}

截取从 offset 个字符开始,向后 length 个字符。

[root@xuel-tmp-shell ~]# var="hello shell"
[root@xuel-tmp-shell ~]# echo ${var:0}
hello shell
[root@xuel-tmp-shell ~]# echo ${var:0:5}
hello
[root@xuel-tmp-shell ~]# echo ${var:6:5}
shell
[root@xuel-tmp-shell ~]# echo ${var:(-1)}
l
[root@xuel-tmp-shell ~]# echo ${var:(-2)}
ll
[root@xuel-tmp-shell ~]# echo ${var:(-5):2}
sh

1.3 字符串替换

格式:${parameter/pattern/string}

${PARAMETER/PATTERN/STRING}
${PARAMETER//PATTERN/STRING}
${PARAMETER/PATTERN}
${PARAMETER//PATTERN}
操作符“/”表示只替换一个匹配的字符串,而操作符“//”表示替换所有匹配的字符串。
如果没有指定替换字符串STRING,那么匹配的内容将被替换为空字符串,即被删除。
[root@xuel-tmp-shell ~]# var="hello shell"
[root@xuel-tmp-shell ~]# echo ${var/shell/world}
hello world

[root@swarm-manager2 Test]# MYSTRING="This is used for replacing string or removing string"
#替换字符串中一个匹配
[root@swarm-manager2 Test]# echo ${MYSTRING/string/characters}
This is used for replacing characters or removing string

##替换所有匹配
[root@swarm-manager2 Test]# echo ${MYSTRING//string/characters}
This is used for replacing characters or removing characters

# 删除一个匹配
[root@swarm-manager2 Test]# echo ${MYSTRING/string/}
This is used for replacing  or removing string

# 删除所有匹配
[root@swarm-manager2 Test]# echo ${MYSTRING//string/}
This is used for replacing  or removing

1.4 字符串删除

$ hujianli="hello fred,/home/fred, this is test var fred"

# 删除变量中匹配到1次的元素     /元素
$ echo ${hujianli/fred}
hello ,/home/fred, this is test var fred


# 删除变量中开头匹配到的元素   /#元素
$ echo ${hujianli/#fred}
hello fred,/home/fred, this is test var fred

# 删除变量中结尾匹配到的元素    /%元素
$ echo ${hujianli/%fred}
hello fred,/home/fred, this is test var

# 删除变量中所有匹配到的元素     //元素
$ echo ${hujianli//fred}
hello ,/home/, this is test var

字符串变量大小写转换

$ echo ${hujianli^^}
HELLO FRED,/HOME/FRED, THIS IS TEST VAR FRED

$ echo ${hujianli,,}
hello fred,/home/fred, this is test var fred

1.5 字符串截取

格式:

${parameter#word} # 删除匹配前缀

${parameter##word}

${parameter%word} # 删除匹配后缀

${parameter%%word}

# 去掉左边,最短匹配模式,##最长匹配模式。

% 去掉右边,最短匹配模式,%%最长匹配模式。

[root@xuel-tmp-shell ~]# url="https://www.baidu.com/index.html"
[root@xuel-tmp-shell ~]# echo ${url#*/}
/www.baidu.com/index.html
[root@xuel-tmp-shell ~]# echo ${url##*/}
index.html

[root@xuel-tmp-shell ~]# echo ${url%/*}
https://www.baidu.com
[root@xuel-tmp-shell ~]# echo ${url%%/*}
https:

1.6 变量状态赋值

${VAR:-string} 如果 VAR 变量为空则返回 string

${VAR:+string} 如果 VAR 变量不为空则返回 string

${VAR:=string} 如果 VAR 变量为空则重新赋值 VAR 变量值为 string

${VAR:?string} 如果 VAR 变量为空则将 string 输出到 stderr

[root@xuel-tmp-shell ~]# url="https://www.baidu.com/index.html"
[root@xuel-tmp-shell ~]# echo ${url:-"string"}
https://www.baidu.com/index.html
[root@xuel-tmp-shell ~]# echo ${url:+"string"}
string
[root@xuel-tmp-shell ~]# unset url
[root@xuel-tmp-shell ~]# echo $url

[root@xuel-tmp-shell ~]# echo ${url:-"string"}
string
[root@xuel-tmp-shell ~]# echo ${url:+"string"}


找出/etc/group下的所有组名称
for i in `cat /etc/group`;do echo ${i%%:*};done

3.2.2. 2. Shell变量操作

2.1 变量替换扩展

2.2 变量字符串操作

2.3 代码总结

#!/usr/bin/env bash
##################### 变量赋值 ##################################################
WORD=car
echo $WORD

###################### 间接参数扩展 ###############################################
PAR=TEMP
TEMP="Thfiles files test TEMP"

echo ${!PAR}
echo $PAR


##################### 大小写修改 ####################################################
# 首字母大写
echo ${TEMP^}
# 全部大写
echo ${TEMP^^}
# 首字母小写
echo ${TEMP,}
# 全部小写
echo ${TEMP,,}
# 首字母小写
echo ${TEMP~}
# 大小写转换
echo ${TEMP~~}


# ----------------- 将当前目录下的所有后缀为txt的文件名转换为小写 --------------
#for file in *.txt ; do
#    mv "$file" "${file,,}"
#done


#############################  字符串移除 ###################################################
MYSTRING="This is used for removing string"

# 从左到右分割显示第一个空格之后的内容
echo ${MYSTRING#* }   # is used for removing string

# 从左到右分割显示最后一个空格之后的内容
echo ${MYSTRING##* }  # string


# 从右到左分割显示第一个空格之后的内容
echo ${MYSTRING% *}     # This is used for removing

# 从右到左分割显示最后一个空格之后的内容
echo ${MYSTRING%% *}    # This


#-------------------------- 最常用的用途是提取文件名的一部分 --------------
FILENAME=linux_bash.txt
echo ${FILENAME%.*}        #移除文件名的后缀    #linux_bash

echo ${FILENAME##*.}       #移除文件名,保留后缀  #txt


FILENAME=/home/yantaol/linux_bash.txt
echo ${FILENAME%/*}        #移除文件名,保留目录名   #/home/yantaol

echo ${FILENAME##*/}       #移除目录名,保留文件名   #linux_bash.txt



################################################## 字符串搜索与替换 #############################
# 操作符“/”表示只替换一个匹配的字符串,而操作符“//”表示替换所有匹配的字符串。如果没有指定替换字符串STRING,那么匹配的内容将被替换为空字符串,即被删除。
MYSTRING="This is used for replacing string or removing string"
# 替换一次
echo ${MYSTRING/string/characters }
# 替换全部
echo ${MYSTRING//string/characters }

# 删除一次
echo ${MYSTRING/string }
echo ${MYSTRING//string }
# 删除全部
echo ${MYSTRING//string/}


############################################### 求字符串长度 ######################################
# 求字符串长度
# ${#PARAMETER}
MYSTRING="Hello World"
echo ${#MYSTRING}

# 子字符串扩展:
#${PARAMETER:OFFSET}
#${PARAMETER:OFFSET:LENGTH}

#这种参数扩展格式将扩展参数值的一部分,从指定的位置开始截取指定长度的字符串,如果省略LENGTH,将截取到参数值的末尾
MYSTRING="This is used for substring expansion."
echo ${MYSTRING:8}    # used for substring expansion.
echo ${MYSTRING:8:10} # used for s


################################################ 使用默认值 ##########################################
#${PARAMETER:-WORD}

#${PARAMETER-WORD}

#如果参数PARAMETER是未定义,或为null时,这种模式会扩展WORD,否则将扩展参数PARAMETER。如果在PARAMETER和WORD之间略去了符号“:”,即上述语法中的第二种格式,只有参数PARAMETER是未定义时,才会使用WORD

unset MYSTRING  # 解除环境变量
echo ${MYSTRING:-Hello World}

unset MYSTRING  # 解除环境变量
MYSTRING=
echo ${MYSTRING:-Hello World}

MYSTRING=Hi
echo ${MYSTRING:-Hello World}

unset MYSTRING  # 解除环境变量
MYSTRING=
# 当变量为空值时,去掉:打印空值,空值也是参数
echo ${MYSTRING-Hello World}


echo "------------------------------------ 华丽的分割线 -----------------------------------------------"
##################################################### 指定默认值 ########################################
#${PARAMETER:=WORD}

#${PARAMETER=WORD}

#这种模式与使用默认值的模式类似,但其区别在于,此种模式不仅扩展WORD,还将WORD赋值给参数PARAMETER,作为PARAMETER的值

echo ${MYSTRING_hu:=Hello World}
echo $MYSTRING_hu

echo ${MYSTRING_hu1=Hello World}
echo $MYSTRING_hu1

echo "------------------------------------ 华丽的分割线 -----------------------------------------------"
#################################################### 使用替代值 ###################################

#${PARAMETER:+WORD}

#${PARAMETER+WORD}

#如果参数PARAMETER是未定义的,或其值为空时,这种模式将不扩展任何内容。如果参数PARAMETER是定义的,且其值不为空,这种模式将扩展WORD,而不是扩展为参数PARAMETER的值。

MYSTRING722=""
echo ${MYSTRING:+ NOTE: MYSTRING seems to be set.}

MYSTRING="Hi"
echo ${MYSTRING:+ NOTE: MYSTRING seems to be set.}

3.2.3. 3 数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小。数组是相同类型的元素按一定顺序排列的集合。 类似与 C 语言,数组元素的下标由 0 开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。

3.1 数组定义

在 Shell 中,用括号来表示数组,数组元素用”空格”符号分割开

3.2 通过元素值集合来创建数组变量

#! /bin/bash

# 定义数组
array=(1 2 3 4 5 6 7 8)
# 输出第 1 个数组元素的值
echo "the first element is ${#array[0]}"
# 输出所有元素的值
echo "the elements of this array are ${array[@]}"
# 输出数组长度
echo "the size of the array is ${#array[@]}"

计算数组的长度

${#array[@]}
或者
${#array[*]}

#array表示数组名称,方括号中的@或者*是通配符,表示匹配所有的元素。

3.3 通过键值对定义数组

#! /bin/bash

# 定义数组
array=([1]=one [4]=four)
# 输出数组长度
echo "the size of the array is  ${#array[@]}"
# 输出索引为 4 的元素的值
echo "the fourth element is ${array[4]}"

3.4 数组元素读取

[root@xuel-tmp-shell ~]# args1=(aa bb cc 1123)
[root@xuel-tmp-shell ~]# echo ${#args1[@]}     #获取数组元素个数
4
[root@xuel-tmp-shell ~]# echo ${args1[0]}
aa
[root@xuel-tmp-shell ~]# echo ${args1[1]}
bb

[root@monitor workspace]# filelist=($(ls))
[root@monitor workspace]# echo ${filelist[*]}
check_url_for.sh check_url_while01.sh check_url_while02.sh func01.sh func02.sh func03.sh urllist.txt

获取数组元素的下标
[root@monitor workspace]# echo ${!filelist[@]}
0 1 2 3 4 5 6

遍历数组

方式1

#! /bin/bash

# 定义数组
array=(Mon Tue Wed Thu Fri Sat Sun)
# 通过下标访问数组
for (( i = 0; i < ${#Ip_array[@]}; i++ )); do
    echo $i ${array[i]}
done

方式2

#! /bin/bash

array=(Mon Tue Wed Thu Fri Sat Sun)
# 获取数组长度
len="${#array[@]}"
# 通过循环结构遍历数组
for ((i=0;i<$len;i++))
do
   echo "${array[$i]}"
done

遍历文件

filelist=($(ls));for i in ${!filelist[@]};do echo ${filelist[$i]};done

3.5 以切片方式获取部分数组元素

#! /bin/bash
#在上面的代码中,第4行定义了一个含有7个元素的数组。第6行从下标为2的数组元素开始,截取其中的4个元素。
linux=("Debian" "RedHat" "Ubuntu" "Suse" "Fedora" "UTS" "CentOS")
# 数组切片
var=${linux[@]:2:4}
echo "$var"

[root@linux chapter7]# ./ex7-19.sh
Ubuntu Suse Fedora UTS

演示将切片结果以数组形式保存的方法。本例将切片的结果赋给了一个新的数组变量,然后输出新的数组的长度,最后通过循环输出所有的数组元素

#! /bin/bash

# 定义数组
linux=("Debian" "RedHat" "Ubuntu" "Suse" "Fedora" "UTS" "CentOS")

# 切片
array=(${linux[@]:2:4})
# 获取新的数组的长度
length="${#array[@]}"
# 输出数组长度
echo "the length of new array is $length"
# 通过循环输出各个元素
for ((i=0;i<$length;i++))
do
   echo "${array[$i]}"
done

3.6 通过declare语句定义关联数组

其基本语法如下:

declare -a array
declare -A dic

在上面的语法中,-a选项表示后面定义的是一个数组,其名称为array。

关联数组 —> shell中的字典

# -A 举例,字典类型的关联数组
declare -A dic
dic=([no1]="hujianli1" [no2]="hujianli2" [no3]="hujianli3")

echo ${dic[no3]}        #hujianli3
#打印所有的key
echo ${!dic[*]}         # no3 no2 no1

#打印所有的value
echo ${dic[*]}          # hujianli3 hujianli2 hujianli1

# 变量key和value
$ for i in ${!dic[*]}; do echo ${i}:${dic[$i]}; done
no3:hujianli3
no2:hujianli2
no1:hujianli1

关联数组必须以大写的declare -A命令来进行声明

$ declare -A array_example
$ array_example=([0]=centos7
                 [1]=centos6
                 [2]=ubuntu
                 [3]=redhat
                 [4]=suse
                 [5]=windows)

$ echo ${array_example[3]}
redhat

$ echo ${array_example[*]}
centos7 centos6 ubuntu redhat suse windows

$ echo ${array_example[@]}
centos7 centos6 ubuntu redhat suse windows

$ echo ${#array_example[@]}
6

# 显示所有的index下标
$ echo ${!array_example[*]}
0 1 2 3 4 5

举例说明

declare -A projects=(
    [test_chatsrv-frontend]="172.20.20.3"
    [test_chatsrv-core]="172.20.20.5"
    [test_chatsrv-storage]="172.20.20.5"
    [test_chatsrv-push]="172.20.20.5"
)

token="xxxxxxxxx"

for project in ${!projects[@]}; do
    client="${projects[${project}]}"
    curl -w '\n' 'http://deploy.ixiaochuan.cn/deploy' -H "Cookie: remember_token=${token};" --data "operation=update&project=${project}&client=${client}" --compressed --silent
done
#!/bin/sh
# @Author: hujianli
# @Date:   2018-11-18 15:03:18
# @Last Modified by:   hujianli
# @Last Modified time: 2018-11-18 15:15:13

: <<EOF
符号*是把原数组中的所有元素(除了用于区别元素的分隔符,通常是空格)当成一个元素复制到新数组中,生的新数组只有一个元素
符号@的含义是把原数组的内容复制到一个新数组中,生成的新数组和原来的是一样的
EOF

declare -a      #显示当前所有的数组
declare -ar BASH_VERSION='([0]="2"
                           [1]="05b"
                           [2]="0"
                           [3]="1"
                           [4]="release"
                           [5]="i386-redhat-linux-gnu")'
declare -a DIRSTACK='()'
declare -a GROUPS='()'
declare -a PIPESTATUS='([0]="0")'
declare -a student='([0]="张三"
    [1]="李四"
    [2]="王小二"
    [3]="李晓明"
    [4]="张四宝")'
declare -a score='([0]="66"
    [1]="70"
    [2]="80"
    [3]="90"
    [4]="98")'

echo ${student[@]}
echo ${student[*]}
#!/bin/sh
# @Author: hujianli
# @Date:   2018-11-18 13:59:12
# @Last Modified by:   hujianli
# @Last Modified time: 2018-11-18 14:04:47
student=("张三" "李四" "王五" "李晓明" "胡建力")
score=(66 70 80 84 99)

N=${#student[*]}        #计算数组的个数总和,赋值给变量N
echo "学生总数为:$N"
i=0
while [[ $i -lt $N ]]; do
    echo -e "\tstudent $[i]的考试成绩为:${score[$i]}"
    i=$(($i+1))
done

3.7 在数组末尾追加新元素

在Shell中,向已有的数组末尾追加新的元素非常方便。在通过索引为数组元素赋值时,如果指定的索引不存在,则Shell会自动添加一个新的元素,并且将指定的值赋给该元素。

演示如何在数组末尾追加新的数组元素

#! /bin/bash
# 定义数组
array=(1 2)
# 输出数组
echo "${array[@]}"
# 向数组末尾追加元素
array[2]=3
array[3]=4
echo "${array[@]}"

演示向关联数组追加新元素的方法

#! /bin/bash
# 定义数组
declare -A array
# 初始化数组
array=([a]=a [b]=b)

echo "the old elements are ${array[@]}"
# 向数组追加元素
array[c]=c
echo "the new elements are ${array[@]}"

3.8 通过循环为数组赋值

#! /bin/bash
# 通过循环为数组赋值
for i in {1..10}
do
   array[$i]=$i
done
# 输出元素的值
echo "${array[@]}"

3.9 数组元素的替换

数组元素替换的基本语法如下:

${array[@|*]/pattern/replacement}

演示如何对数组进行替换,以及如何将替换的结果赋给一个新的数组变量。

#! /bin/bash
# 定义数组
a=(1 2 3 4 5)
# 输出替换结果
echo "the result is ${a[@]/3/100}"
# 输出原始数组
echo "the old array is ${a[@]}"
# 将替换结果赋给一个数组变量
a=(${a[@]/3/100})
# 输出新的数组变量的值
echo "the new array is ${a[@]}"

该程序的执行结果如下:

[root@linux chapter7]# ./ex7-23.sh
the result is 1 2 100 4 5
the old array is 1 2 3 4 5
the new array is 1 2 100 4 5

3.10 删除数组

与删除其他的Shell变量一样,用户可以使用unset命令来删除某个数组元素,其基本语法如下:

unset array[n]

删除数组中的元素

#! /bin/bash

linux=("Debian" "RedHat" "Ubuntu" "Suse" "Fedora" "UTS" "CentOS")
# 输出原始数组长度
echo "the length of original array is ${#linux[@]}"
# 输出数组的原始值
echo "the old array is ${linux[@]}"
# 删除下标为 3 的元素
unset linux[3]
 输出新的数组的长度
echo "the length of new array is ${#linux[@]}"
# 输出新的数组的值
echo "the new array is ${linux[@]}"

删除整个数组

#! /bin/bash

linux=("Debian" "RedHat" "Ubuntu" "Suse" "Fedora" "UTS" "CentOS")
# 删除整个数组
unset linux
echo "${linux[@]}"

3.11 数组的其它操作

复制数组

所谓复制数组,是指创建一个已经存在的数组的副本。也就是将一个数组的内容全部存储到另外一个新的数组中。

在Shell中,用户可以通过以下语法来实现数组的复制:
newarray=("${array[@]}")

连接数组

连接数组是指将2个数组的数组元素连接在一起,变成一个大的数组。新的数组依次包含2个数组的所有的元素。数组连接的语法如下:

("$array1[@]}" "${array2[@]}")

示例

#! /bin/bash

# 定义 2 个数组
linux=("Debian" "RedHat" "Ubuntu" "Suse" "Fedora" "UTS" "CentOS")
shell=("bash" "csh" "ksh" "rsh" "sh" "rc" "tcsh")

# 连接数组
linuxshell=("${linux[@]}" "${shell[@]}")

# 输出合并后的数组
echo "the new array is ${linuxshell[@]}"
# 输出新的数组的长度
echo "the length of new array is ${#linuxshell[@]}"

加载文件内容到数组

#! /bin/bash
# 加载文件内容
content=(`cat "demo.txt"`)
# 通过循环输出数组内容
for s in "${content[@]}"
do
   echo "$s"
done

3.2.4. 4 字符显示颜色

字体颜色           字体背景颜色            显示方式
30:黑                40:黑
31:红                41:深红              0:终端默认设置
32:绿                42:绿                   1:高亮显示
33:黄                43:黄色              4:下划线
34:蓝色            44:蓝色             5:闪烁
35:紫色            45:紫色             7:反白显示
36:深绿            46:深绿             8:隐藏
37:白色            47:白色
格式:
\033[1;31;40m|  # 1 是显示方式,可选。31 是字体颜色。40m 是字体背景颜色。
\033[0m | # 恢复终端默认颜色,即取消颜色设置。
  • 显示方式

for i in {1..8};do echo -e "\033[$i;31;40m hello world \033[0m";done
  • 字体颜色

for i in {30..37};do echo -e "\033[$i;40m hello world \033[0m";done
  • 背景颜色

for i in {40..47};do echo -e "\033[47;${i}m hello world! \033[0m";done
#!/usr/bin/env bash
#usage:xxx
#scripts_name:xxx.sh
# 文本颜色是由对应的色彩码来描述的。其中包括:重置=0,黑色=30,红色=31,绿色=32,
#  黄色=33,蓝色=34,洋红=35,青色=36,白色=37。


echo -e "\e[1;31m This is red text \e[0m"
echo -e "\e[1;32m This is green text \e[0m"
echo -e "\e[1;33m This is yellow text \e[0m"
echo -e "\e[1;34m This is blue text \e[0m"
echo -e "\e[1;35m This is Magenta text \e[0m"
echo -e "\e[1;36m This is 青色 text \e[0m"
echo -e "\e[1;37m This is white text \e[0m"
echo
echo

#对于彩色背景,经常使用的颜色码是:重置=0,黑色=40,红色=41,绿色=42,黄色=43,
# 蓝色=44,洋红=45,青色=46,白色=47。
echo -e "\e[1;41m Green Background \e[0m"
echo -e "\e[1;42m Green Background \e[0m"
echo -e "\e[1;43m Green Background \e[0m"
echo -e "\e[1;44m Green Background \e[0m"
echo -e "\e[1;45m Green Background \e[0m"
echo -e "\e[1;46m Green Background \e[0m"
echo -e "\e[1;47m Green Background \e[0m"


#定义一个颜色的函数
echo_color (){
    local color=$1
    local info=$2
    case "$color" in
    red)
        echo -e "\e[1;31m ${info} \e[0m"
       ;;
    green)
        echo -e "\e[1;32m ${info} \e[0m"
       ;;
    yellow)
        echo -e "\e[1;33m ${info} \e[0m"
       ;;
    blue)
        echo -e "\e[1;34m ${info} \e[0m"
       ;;
    Magenta)
        echo -e "\e[1;35m ${info} \e[0m"
    ;;
    cyan-blue)
        echo -e "\e[1;36m ${info} \e[0m"
    ;;
    esac

}


echo_color red "哈哈哈哈哈哈哈"
echo_color green "哈哈哈哈哈哈哈"
echo_color yellow "哈哈哈哈哈哈哈"
echo_color blue "哈哈哈哈哈哈"
echo_color Magenta "哈哈哈哈哈哈"