Shell(十二):别名、列表及数组

发布时间 2023-10-18 17:01:39作者: 无虑的小猪

1、别名

  bash Shell的别名实际上是一种避免输入长命令的手段,是为长命令起一个新的名字作为其缩写。别名的关键字是alias,命令的基本格式如下:

alias alias-name="original-command"

  alias 是执行别名命令的关键字,alias-name是用户所指定的别名,original-command是所起别名所对应的命令及其参数,当original-command是以空格分隔的字符串时,就要将original-command用引号引起来。注意:等号两边不能有空格。

  allias命令用法:

0

  将dir作为ls命令的别名,执行dir就相当于执行了ls命令,就能列出当前目录下的所有文件。

  删除已经设置的别名,可以使用unalias命令,unalias是一个内建命令,有如下两种格式:

unalias [-a] [alias-name]

  unalias命令后面可以跟 -a 参数或alias-name,即别名,unalias -a 命令表示删除所有已设置的别名,而unalias alias-name 表示仅将别名 alias-name 删除。

2、列表

  列表由一串命令用与运算(&&)和或运算(||)连接而成,用与运算连接的列表称为与列表(and list),用或运算连接的列表称为或列表(or list)。

  与列表的基本格式为:

命令1 && 命令2 && 命令3 && ... && 命令n

  上述格式的与列表从左至右依次执行命令,直到命令返回FALSE时,与列表执行终止。

  或列表的基本格式和与列表类似,仅将&&符号改为||符号,为

命令1 || 命令2 || 命令3 || ... || 命令n

  或列表依然从左至右依次执行命令,它是当某命令返回TRUE时,或列表执行终止。以上所提及的TRUE和FALSE是由返回的退出状态来决定的,若退出状态为0,则为TRUE,否则为FALSE。

  新建 andlist1.sh 脚本,详情如下:

#!/bin/bash

# if条件是一个与列表
if [ -n "$1" ] && echo "The lst args=$1" && [ -n "$2" ] && echo "The 2nd args=$2"
then
    # 只有与列表命令都执行完,才执行下面的命令
    echo "At least TWO args are passed to this script."
else
    echo "Less than TWO args are passed to this script."
fi

exit 0

  andlist1.sh 脚本用一个if/then结构判断该脚本是否带了两个以上的参数,if条件用一个与列表表示,若$1非空,才执行 echo "The 1st args=$1"命令,否则与列表立即结束,当$1非空时,判断$2是否为空,若非空,才执行echo "The 2nd args=$2"命令,此时,与列表命令全部执行完毕,返回TRUE值,if/then结构才执行then语句段的命令。

  下面分别给出 andlist1.sh 脚本带1个参数和2个参数时的执行结果:

0

  andlist1.sh 脚本的执行结果可看出,当andlist1.sh带有1个输入参数时,输出else语句段的内容,当andlist1.sh带有2个输入参数时,输出then语句段内容。

3、数组

3.1、数组的基本用法

  数组(Array)是一个由若干同类型变量组成的集合,引用这些变量时可用同一名字。数组均由连续的存储单元组成,最低地址对应于数组的第一个元素,最高地址对应于最后一个元素。

  bash Shell只支持一维数组,数组从0开始标号,以array[x]表示数组元素,那么,array[0]就表示array数组的第1个元素,array[1]表示array数组的第2个元素、array[x]表示array数组的第x+1个元素。

  bash Shell取得数组值(即引用一个数组元素)的命令格式如下:

$(array[x])

  注意:上述格式中,$符号后面的花括号必不可少。

  新建 arr01.sh 脚本,详情如下:

#!/bin/bash

# 下面对city数组赋值
city[0]=Nanjing        # 对第1个数组元素赋值 
city[1]=Beijing        # 对第2个数组元素赋值
city[9]=Melbourne    # 对第10个数组赋值,Shell允许数组空缺元素
city[15]=NewYork    # 对第16个数组元素赋值

# 以下输出 city 数组的值
echo "city[0]=${city[0]}"
echo "city[1]=${city[1]}"
echo "city[9]=${city[9]}"
echo "city[15]=${city[15]}"
echo "city[2]=${city[2]}"    # 打印未初始化数组的值
echo "city[10]=${city[10]}"

  

arr01.sh 脚本新建city数组,并对其中的元素赋值。对city数组的第1个和第2个数组元素赋值之后,直接对city数组的第10个数组元素赋值,再次对city数组的第16个数组元素赋值,然后打印city数组的值。
脚本 arr01.sh 执行结果如下:
0

  city数组的第1个、第2个、第10个和第16个元素报错了所赋的给它的值,说明在Shell脚本中,允许数组空缺元素,即可以不连续地给数组赋值,数组的部分元素是没有被初始化的。city[2]和city[10]两个元素是未被初始化的,其值为空。

  可以用 圆括号 将一组值赋给数组,新建 arr02.sh 脚本,详情如下:

#!/bin/bash

# 用圆括号将一组值赋给city数组
city=(Nanjing Beijing Melbourne NewYork)

# 输出标号从 0 到 5 的city数组值
echo "city[0]=${city[0]}"
echo "city[1]=${city[1]}"
echo "city[2]=${city[2]}"
echo "city[3]=${city[3]}"
echo "city[4]=${city[4]}"    # 打印未初始化数组的值
echo "city[5]=${city[5]}" 

  执行结果如下:

0

  city数组从0到3号的元素一次保存了圆括号内的四个城市名,city数组从标号4开始的元素未被初始化。说明用圆括号结构对数组赋值时,在默认情况下,从数组第0个元素开始赋值,将圆括号内以空格为分隔符,一次赋给数组元素。

  圆括号从其他元素开始给数组赋值,新建 arr03.sh 脚本,详情如下:

#!/bin/bash

# [10] 指定city数组标号为10的元素的值
city=(Nanjing [10]=Atlanta Massachusetts Marseilles)


echo "city[0]=${city[0]}"
echo "city[1]=${city[1]}"
echo "city[10]=${city[10]}"
echo "city[11]=${city[11]}"
echo "city[12]=${city[12]}"
echo "city[13]=${city[13]}"

  执行结果如下:

0

  圆括号结构对数组赋值可以指定所赋元素的标号,并以此标号为起点,继续下面的赋值。既然圆括号内允许对数组指定元素进行赋值,可按照任意顺序指定任意元素对数组赋值,新建 arr04.sh 脚本,详情如下:

#!/bin/bash

# 以任意顺序指定位置为数组赋值
city=([2]=Nanjing [10]=Atlanta [1]=Massachusetts [5]=Marseilles)

echo "city[0]=${city[1]}"
echo "city[1]=${city[2]}"
echo "city[10]=${city[5]}"
echo "city[11]=${city[10]}"

  执行结果如下:

0

  bash Shell默认将变量看做是只有一个元素的数组,而且@和*符号都可以从来表示数组的元素。

0

  定义变量onearr,然后打印onearr[@]、onearr[*]、onearr[0]和onearr[1]的值,左后输出onearr数组的长度。可以看出 onearr[@]、onearr[*]、onearr[0]为onearr变量的值 - WebAPIS。而onearr[1]=0,说明onearr[1]未被赋值,而且onearr数组的长度是1。

  在数组中,@ 和 * 符号与位置参数类似,表示"全部",即array[@]和array[*]都表示array数组的所有元素。@ 和 * 符号最常见的应用是打印数组的所有元素。

  新建 arr05.sh 脚本,详情如下:

#!/bin/bash

# 数组赋值
city=(Nanjing Beijing Melbourne NewYork)

# @ 与 * 等价,代表全部元素
for i in ${city[@]}
do
    echo  $i
done

  使用 @ 和 * 符号是遍历数组的所有元素的通用格式,for循环中@符号替换成*符号同样可以遍历数组的所有元素。

  arr05.sh 脚本 执行结果如下:

0

  数组赋值可以不是连续的,若一个数组不连续的赋值,for循环和@只打印被赋值的元素,不打印未赋值的元素。

  新建 arr06.sh 脚本,详情如下:

#!/bin/bash

# 用引号赋包含空格的字符串
city[1]="Hong Kong"
city[100]=Massachusetts
city[101]="New York"
city[10000]=Atlanta

# 需要用引号将 ${city[@]}引起
for i in "${city[@]}"
do
    echo $i
done

  对city数组进行不连续赋值,分别对city数组的1号、100号、101号和10000号元素赋值,其中city[1]包含空格,因而赋值时需要用引号将所赋字符串引起来,然后同样利用for循环和@输出city数组的所有元素,由于city数组中包含了空格,因此用引号将${city[@]}引起来。

  arr06.sh 脚本执行结果如下:

0

3.2、数组特殊用法

  新建arr07.sh 脚本,内容如下:

#!/bin/bash

# 建立数组
city=(Nanjing Atlanta Massachusetts Marseilles)

echo "Extractinng Substring"    # 演示抽取子串功能
echo ${city[*]:0}        # 抽取整个数组
echo ${city[*]:1}        # 抽取从第1个元素到结束的数组
echo ${city[*]:3}        # 抽取从第3个元素到结束的数组
echo ${city[*]:0:2}        # 抽取从第0个元素开始的2个元素
echo ""
echo "Removing Substring"    # 演示删除子串功能
echo ${city[*]#M*a}        # 删除从M到a的最短子串
echo ${city[*]##M*a}        # 删除从M到a的最长子串
echo ""
echo "Replacing Substring"    # 演示替换子串功能
echo ${city[*]/M*s/Year}    # 替换第1此与M*s匹配的子串
echo ${city[*]//M*s/Year}    # 替换所有与M*s匹配的子串

  arr07.sh 演示了抽取子串、删除子串和替换子串三种功能。执行结果如下:

0

  数组可以存放read命令所读入的用户输入参数,而且内建命令unset可用于清空数组元素或整个数组。

  新建 arr08.sh 脚本,详情如下:

#!/bin/bash

# 将 arrivedcity 声明为数组 
declare -a arrivedcity

echo "What city have you been arrived?"
echo "The input should be speparated from each other by a SPACE"
# 用户输入存储到 arrivedcity 数组
read -a arrivedcity
echo ""

# for 循环输出数组的全部内容
for i in "${arrivedcity[@]}"
do
    echo $i
done

echo "length of array:${#arrivedcity[@]}."
echo "Executing UNSET operation......"
unset arrivedcity[1]        # 清空 arrivedcity[1]元素
echo "length of array:${#arrivedcity[@]}."
echo "Executing UNSET operation......"
unset arrivedcity        # 清空整个数组
echo "length of array:${#arrivedcity[@]}"

  arr08.sh 脚本首先将arrivedcity声明为数组类型,在用 read -a 命令将用户输入存储到 arrivedcity 数组,用于输入以空格分隔。利用unset命令清空一个元素和整个数组后,分别输出 arrivedcity 数组的长度。

  脚本 arr08.sh 执行结果如下:

   Shell数组还可以进行数组连接,新建 arr09.sh 脚本,内容如下:

#!/bin/bash
# 数组的连接操作

# 初始化两个数组,person 数组不连续的进行赋值
city=(Beijing Shanghai Nanjing)
person=(Cai [5]=Wu Tang)

# 声明combine数组
declare -a combine
# combine是city和person的连接
combine=(${city[@]} ${person[@]})

# 用while循环输出combine数组内容
element_count=${#combine[@]}
index=0
while [ "$index" -lt "$element_count" ]
do
    echo "Element[$index]=${combine[$index]}"
    let "index=$index+1"
done
echo ""
echo "-----------------------------"

unset combine
combine[0]=${city[@]}
combine[1]=${person[@]}
# 再次输出combine
# 用while循环输出combine数组内容
element_count=${#combine[@]}
index=0
while [ "$index" -lt "$element_count" ]
do
        echo "Element[$index]=${combine[$index]}"
        let "index=$index+1"
done 
echo ""

  arr09.sh脚本定义city和person两个数组,并对其赋值,对person数组的赋值时不连续的,person[0]、person[5]、person[6]三个元素被赋值。声明combine数组,然后将city和person数组连接,并赋给combine数组;也可利用combine[0]和combine[1],用两个表达式分别赋值,最后利用while循环输出combine数组的值。

  arr09.sh 脚本执行结果如下:

0
 

3.3、数组实现简单的数据结构

  数据结构是指相互之间存在的一种或多种特定关系的数据元素的集合,直接影响到程序的运行速度和存储效率。bash Shell不直接支持如堆栈、队列、链表等数据结构。但通过数组bash Shell可以很容易实现线性数据结构。

  通过数组实现堆栈,新建 stack.sh 脚本,内容如下:

#!/bin/bash
# 数组实现堆栈

# 堆栈所能存放元素的最大值
MAXTOP=50

# 定义栈顶指针,初始值是$MAXTOP
TOP=$MAXTOP
# 定义一个临时全局变量,存放处栈元素,初始值为空
TEMP=
# 定义全局数组STACK
declare -a STACK

# push 函数是进栈操作,可同时将多个元素压入堆栈
push(){
    if [ -z "$1" ]
    then
        return
    fi
    
    # until循环将push函数所有的参数都压入堆栈
    until [ $# -eq 0 ]
    do
        let TOP=TOP-1
        STACK[$TOP]=$1
        shift
    done
    return
}

# pop 函数是出栈操作,执行pop函数使得栈顶元素出栈
pop(){
    if [ "$TOP" -eq "$MAXTOP" ]
    then
        return
    fi
    
    TEMP=${STACK[$TOP]}
    unset STACK[$TOP]
    let TOP=TOP+1
    return
}

# status函数用于显示当前堆栈内的元素,以及TOP指针和TEMP变量
status(){
    echo "========================="
    echo "==========STACK=========="
    for i in ${STACK[@]}
    do
        echo $i
    done
    echo ""
    echo "Stack Pointer=$TOP"
    echo "Just poped \""$TEMP"\" off the stack"
    echo "==============="
    echo
}

push lj        # 压入一个元素
status
push zs ls1 ww    # 压入三个元素
status

pop        # 出栈
pop        # 出栈
status
push edsfs    # 压入一个元素
push dsfjs dbfdsfds    # 压入两个元素
status

  stack.sh脚本利用数组实现了堆栈操作。stach.sh定义了三个函数:push、pop、status,push函数将字符串压入堆栈,pop函数能弹出栈顶元素,status函数打印当前堆栈的状态信息。

  stack.sh脚本定义了四个全局变量:MAXTOP记录了堆栈的最大长度,即堆栈最多可以包含MAXTOP个元素;TOP记录栈顶指针,即指向当前栈顶元素的数组标号;TEMP记录最近出栈的元素;数组STACK记录了堆栈内容。

  push函数,紧跟任意个输入参数,可以同时将多个元素压入堆栈,push函数首先利用if/then结构判断位置参数$1是否为空,若$1为空,说明无字符串需要入栈,push函数立即结束;否则,说明存在若干元素需要入栈。接着,push函数使用了until循环结构逐个将输入参数压入堆栈,循环体内的入栈操作首先将TOP指针减1,即TOP指针移动到一个新位置,然后STACK[$TOP]=$1语句将位置参数$1赋给TOP指针所对应的STACK数组元素,这样的赋值方式使得堆栈的第1个元素存储在STACK数组的MAXTOP-1位置、第2个元素存储在STACK数组的MAXTOP-2位置,第3个元素存储在STACK数组的MAXTOP-3位置,以此类推。

  将一个位置参数压入堆栈后,执行shift命令,shift命令完成两个功能:第一,所有的位置参数左移1位,即$2移到$1的位置,$3移到$2的位置,以此类推;第二,$#变量值减1。依赖shift命令的两个功能,下一次的until循环就可以对下一个位置参数进行处理,被处理的位置参数彪悍依然是$1,直到$#变量等于0时,所有的位置参数处理完毕,until循环结束,push函数随之结束。

  pop函数,首先判断TOP是否等于MAXTOP,若是,则表明堆栈中无元素,无需执行pop操作,否则,利用STACK[$TOP]赋值语句,将栈顶元素赋给TEMP变量,清空STACK[$TOP]的值,并将TOP指针加1,TOP指针就指向了下一个栈顶元素。status利用for循环输出STACK数组的所有元素,即堆栈的全部内容,并输出TOP变量和TEMP变量。

  stack.sh脚本 执行结果如下:

0