(八)shell程式設計之陣列,字串還有高階變數
阿新 • • 發佈:2021-06-14
陣列 array
陣列介紹
變數:儲存單個元素的記憶體空間
陣列:儲存多個元素的連續的記憶體空間,相當於多個變數的集合
陣列名和索引
索引的編號從0開始,屬於數值索引
索引可支援使用自定義的格式,而不僅是數值格式,即為關聯索引,bash 4.0版本之後開始支援
bash的陣列支援稀疏格式(索引不連續)
宣告陣列
#普通陣列可以不事先宣告,直接使用
declare -a ARRAY_NAME
#關聯陣列必須先宣告,再使用
declare -A ARRAY_NAME
注意:兩者不可相互轉換
陣列賦值
陣列元素的賦值
(1) 一次只賦值一個元素
ARRAY_NAME[INDEX]=VALUE
範例:
weekdays[0]="Sunday"
weekdays[4]="Thursday"
(2) 一次賦值全部元素
ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
範例:
title=("ceo" "coo" "cto")
num=({0..10})
alpha=({a..g})
file=( *.sh )
(3) 只賦值特定元素
ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
(4) 互動式陣列值對賦值
read -a ARRAY
範例:
[root@centos8 ~]# declare -A course [root@centos8 ~]# declare -a course -bash: declare: course: cannot convert associative to indexed array [root@centos8 ~]# file=( *.sh ) [root@centos8 ~]# declare -A file -bash: declare: file: cannot convert indexed to associative array
範例:
[root@ubuntu1804 ~]# i=a [root@ubuntu1804 ~]# j=1 [root@ubuntu1804 ~]# declare -A arr [root@ubuntu1804 ~]# arr[$i$j]=long [root@ubuntu1804 ~]# j=2 [root@ubuntu1804 ~]# arr[$i$j]=king [root@ubuntu1804 ~]# echo ${arr[*]} long king [root@ubuntu1804 ~]# echo ${arr[a1]} long [root@ubuntu1804 ~]# echo ${arr[a2]} king
顯示所有陣列
declare -a
範例:
[root@centos8 ~]# declare -a
declare -a BASH_ARGC=()
declare -a BASH_ARGV=()
declare -a BASH_COMPLETION_VERSINFO=([0]="2" [1]="7")
declare -a BASH_LINENO=()
declare -ar BASH_REMATCH=()
declare -a BASH_SOURCE=()
declare -ar BASH_VERSINFO=([0]="4" [1]="4" [2]="19" [3]="1" [4]="release"
[5]="x86_64-redhat-linux-gnu")
declare -a DIRSTACK=()
declare -a FUNCNAME
declare -a GROUPS=()
declare -a PIPESTATUS=([0]="0")
引用陣列
引用特定的陣列元素
${ARRAY_NAME[INDEX]}
#如果省略[INDEX]表示引用下標為0的元素
範例:
[root@centos8 ~]# declare -a title=([0]="ceo" [1]="coo" [2]="cto")
[root@centos8 ~]# echo ${title[1]}
coo
[root@centos8 ~]# echo ${title}
ceo
[root@centos8 ~]# echo ${title[2]}
cto
[root@centos8 ~]# echo ${title[3]}
引用陣列所有元素
${ARRAY_NAME[*]}
${ARRAY_NAME[@]}
範例:
[root@centos8 ~]# echo ${title[@]}
ceo coo cto
[root@centos8 ~]# echo ${title[*]}
ceo coo cto
陣列的長度,即陣列中元素的個數
${#ARRAY_NAME[*]}
${#ARRAY_NAME[@]}
範例:
[root@centos8 ~]# echo ${#title[*]}
3
刪除陣列
刪除陣列中的某元素,會導致稀疏格式
unset ARRAY[INDEX]
範例:
[root@centos8 ~]# echo ${title[*]}
ceo coo cto
[root@centos8 ~]# unset title[1]
[root@centos8 ~]# echo ${title[*]}
ceo cto
刪除整個陣列
unset ARRAY
範例:
[root@centos8 ~]# unset title
[root@centos8 ~]# echo ${title[*]}
陣列資料處理
陣列切片:
${ARRAY[@]:offset:number}
offset #要跳過的元素個數
number #要取出的元素個數
#取偏移量之後的所有元素
{ARRAY[@]:offset}
範例:
[root@centos8 ~]# num=({0..10})
[root@centos8 ~]# echo ${num[*]:2:3}
2 3 4
[root@centos8 ~]# echo ${num[*]:6}
6 7 8 9 10
向陣列中追加元素:
ARRAY[${#ARRAY[*]}]=value
ARRAY[${#ARRAY[@]}]=value
範例:
[root@centos8 ~]# num[${#num[@]}]=11
[root@centos8 ~]# echo ${#num[@]}
12
[root@centos8 ~]# echo ${num[@]}
0 1 2 3 4 5 6 7 8 9 10 11
關聯陣列
declare -A ARRAY_NAME
ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2‘...)
注意:關聯陣列必須先宣告再呼叫
範例
[root@centos8 ~]# name[ceo]=long
[root@centos8 ~]# name[cto]=wang
[root@centos8 ~]# name[coo]=zhang
[root@centos8 ~]# echo ${name[ceo]}
zhang
[root@centos8 ~]# echo ${name[cto]}
zhang
[root@centos8 ~]# echo ${name[coo]}
zhang
[root@centos8 ~]# echo ${name}
zhang
[root@centos8 ~]# declare -A name
-bash: declare: name: cannot convert indexed to associative array
[root@centos8 ~]# unset name
[root@centos8 ~]# declare -A name
[root@centos8 ~]# name[ceo]=long
[root@centos8 ~]# name[cto]=wang
[root@centos8 ~]# name[coo]=zhang
[root@centos8 ~]# echo ${name[coo]}
zhang
[root@centos8 ~]# echo ${name[ceo]}
long
[root@centos8 ~]# echo ${name[cto]}
wang
[root@centos8 ~]# echo ${name[*]}
long wang zhang
範例:關聯陣列
[root@centos8 ~]# declare -A student
[root@centos8 ~]# student[name1]=lijun
[root@centos8 ~]# student[name2]=ziqing
[root@centos8 ~]# student[age1]=18
[root@centos8 ~]# student[age2]=16
[root@centos8 ~]# student[gender1]=m
[root@centos8 ~]# student[city1]=nanjing
[root@centos8 ~]# student[gender2]=f
[root@centos8 ~]# student[city2]=anhui
[root@centos8 ~]# student[gender2]=m
[root@centos8 ~]# student[name50]=alice
[root@centos8 ~]# student[name3]=tom
[root@centos8 ~]# for i in {1..50};do echo student[name$i]=${student[name$i]};done
範例:編寫指令碼,定義一個數組,陣列中的元素對應的值是/var/log目錄下所有以.log結尾的檔案;統計出其下標為偶數的檔案中的行數之和
#!/bin/bash
#
declare -a files
files=(/var/log/*.log)
declare -i lines=0
for i in $(seq 0 $[${#files[*]}-1]); do
if [ $[$i%2] -eq 0 ];then
let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1)
fi
done
echo "Lines: $lines"
字串處理
基於偏移量取字串
#返回字串變數var的字元的長度,一個漢字算一個字元
${#var}
#返回字串變數var中從第offset個字元後(不包括第offset個字元)的字元開始,到最後的部分,
offset的取值在0 到 ${#var}-1 之間(bash4.2後,允許為負值)
${var:offset}
#返回字串變數var中從第offset個字元後(不包括第offset個字元)的字元開始,長度為number的部分
${var:offset:number}
#取字串的最右側幾個字元,取字串的最右側幾個字元, 注意:冒號後必須有一空白字元
${var: -length}
#從最左側跳過offset字元,一直向右取到距離最右側lengh個字元之前的內容,即:掐頭去尾
${var:offset:-length}
#先從最右側向左取到length個字元開始,再向右取到距離最右側offset個字元之間的內容,注意:-
length前空格,並且length必須大於offset
${var: -length:-offset}
範例:
[root@centos8 script40]# str=abcdef我你他
[root@centos8 script40]# echo ${#str}
9
[root@centos8 script40]# echo ${str:2}
cdef我你他
[root@centos8 script40]# echo ${str:2:3}
cde
[root@centos8 script40]# echo ${str:-3}
abcdef我你他
[root@centos8 script40]# echo ${str: -3}
我你他
[root@centos8 script40]# echo ${str:2:-3}
cdef
[root@centos8 script40]# echo ${str: -2:-3}
-bash: -3: substring expression < 0
[root@centos8 script40]# echo ${str: -3:-2}
我
[root@centos8 script40]# echo ${str:-3:-2}
abcdef我你他
[root@centos8 script40]# echo ${str: -3:-2}
我
[root@centos8 script40]# echo ${str: -5:-2}
ef我
基於模式取子串
#其中word可以是指定的任意字元,自左而右,查詢var變數所儲存的字串中,第一次出現的word, 刪除字
符串開頭至第一次出現word字串(含)之間的所有字元,即懶惰模式,以第一個word為界刪左留右
${var#*word}
#同上,貪婪模式,不同的是,刪除的是字串開頭至最後一次由word指定的字元之間的所有內容,即貪婪模
式,以最後一個word為界刪左留右
${var##*word}
範例:
[root@centos8 ~]# file="var/log/messages"
[root@centos8 ~]# echo ${file#*/}
log/messages
[root@centos8 ~]# echo ${file##*/}
messages
#其中word可以是指定的任意字元,功能:自右而左,查詢var變數所儲存的字串中,第一次出現的word,
刪除字串最後一個字元向左至第一次出現word字串(含)之間的所有字元,即懶惰模式,以從右向左的第
一個word為界刪右留左
${var%word*}
#同上,只不過刪除字串最右側的字元向左至最後一次出現word字元之間的所有字元,即貪婪模式,以從右向
左的最後一個word為界刪右留左
${var%%word*}
範例:
[root@centos8 ~]# file="var/log/messages"
[root@centos8 ~]# echo ${file%/*}
var/log
[root@centos8 ~]# echo ${file%%/*}
var
範例:
[root@centos8 ~]# url=http://www.longxuan.com:8080
[root@centos8 ~]# echo ${url##*:}
8080
[root@centos8 ~]# echo ${url%%:*}
http
查詢替換
#查詢var所表示的字串中,第一次被pattern所匹配到的字串,以substr替換之
${var/pattern/substr}
#查詢var所表示的字串中,所有能被pattern所匹配到的字串,以substr替換之
${var//pattern/substr}
#查詢var所表示的字串中,行首被pattern所匹配到的字串,以substr替換之
${var/#pattern/substr}
#查詢var所表示的字串中,行尾被pattern所匹配到的字串,以substr替換之
${var/%pattern/substr}
查詢並刪除
#刪除var表示的字串中第一次被pattern匹配到的字串
${var/pattern}
刪除var表示的字串中所有被pattern匹配到的字串
${var//pattern}
刪除var表示的字串中所有以pattern為行首匹配到的字串
${var/#pattern}
刪除var所表示的字串中所有以pattern為行尾所匹配到的字串
${var/%pattern}
字元大小寫轉換
#把var中的所有小寫字母轉換為大寫
${var^^}
#把var中的所有大寫字母轉換為小寫
${var,,}
高階變數
範例:
[root@centos8 ~]# title=ceo
[root@centos8 ~]# name=${title-long}
[root@centos8 ~]# echo $name
ceo
[root@centos8 ~]# title=
[root@centos8 ~]# name=${title-long}
[root@centos8 ~]# echo $name
[root@centos8 ~]# unset title
[root@centos8 ~]# name=${title-long}
[root@centos8 ~]# echo $name
long
範例:
[root@centos8 ~]# title=ceo
[root@centos8 ~]# name=${title:-long}
[root@centos8 ~]# echo $name
ceo
[root@centos8 ~]# title=
[root@centos8 ~]# name=${title:-long}
[root@centos8 ~]# echo $name
long
[root@centos8 ~]# unset title
[root@centos8 ~]# name=${title:-long}
[root@centos8 ~]# echo $name
long
高階變數用法-有型別變數
Shell變數一般是無型別的,但是bash Shell提供了declare和typeset兩個命令用於指定變數的型別,兩
個命令是等價的
declare [選項] 變數名
選項:
-r 宣告或顯示只讀變數
-i 將變數定義為整型數
-a 將變數定義為陣列
-A 將變數定義為關聯陣列
-f 顯示已定義的所有函式名及其內容
-F 僅顯示已定義的所有函式名
-x 宣告或顯示環境變數和函式,相當於export
-l 宣告變數為小寫字母 declare -l var=UPPER
-u 宣告變數為大寫字母 declare -u var=lower
-n make NAME a reference to the variable named by its value
變數間接引用
eval命令
eval命令將會首先掃描命令列進行所有的置換,然後再執行該命令。該命令適用於那些一次掃描無法實
現其功能的變數,該命令對變數進行兩次掃描
範例:
[root@centos8 ~]# CMD=whoami
[root@centos8 ~]# echo $CMD
whoami
[root@centos8 ~]# eval $CMD
root
[root@centos8 ~]# n=10
[root@centos8 ~]# echo {0..$n}
{0..10}
[root@centos8 ~]# eval echo {0..$n}
0 1 2 3 4 5 6 7 8 9 10
[root@centos8 ~]# for i in `eval echo {1..$n}` ;do echo i=$i ;done
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
i=10
[root@centos8 ~]# i=a
[root@centos8 ~]# j=1
[root@centos8 ~]# $i$j=hello
-bash: a1=hello: command not found
[root@centos8 ~]# eval $i$j=hello
[root@centos8 ~]# echo $i$j
a1
[root@centos8 ~]# echo $a1
hello
間接變數引用
如果第一個變數的值是第二個變數的名字,從第一個變數引用第二個變數的值就稱為間接變數引用
variable1的值是variable2,而variable2又是變數名,variable2的值為value,間接變數引用是指通過
variable1獲得變數值value的行為
variable1=variable2
variable2=value
#示例:
i=1
$1=wang
bash Shell提供了兩種格式實現間接變數引用
#方法1
#變數賦值
eval tempvar=\$$variable1
#顯示值
eval echo \$$variable1
eval echo '$'$variable1
#方法2
#變數賦值
tempvar=${!variable1}
#顯示值
echo ${!variable1}
範例:
[root@centos8 ~]# ceo=name
[root@centos8 ~]# name=long
[root@centos8 ~]# echo $ceo
name
[root@centos8 ~]# echo $$ceo
33722ceo
[root@centos8 ~]# echo $$
33722
[root@centos8 ~]# echo \$$ceo
$name
[root@centos8 ~]# eval echo \$$ceo
long
[root@centos8 ~]# eval tmp=\$$ceo
[root@centos8 ~]# echo $tmp
long
[root@centos8 ~]# echo ${!ceo}
long
範例:
[root@server ~]# N1=N2
[root@server ~]# N2=longwang
[root@server ~]# eval NAME=\$$N1
[root@server ~]# echo $NAME
longwang
[root@server ~]# NAME=${!N1}
[root@server ~]# echo $NAME
longwang
範例: 批量建立使用者
#!/bin/bash
n=$#
[ $n -eq 0 ] && { echo "Usage: `basename $0` username..." ; exit 2; }
for i in `eval echo {1..$n}`;do
user=${!i}
id $user &> /dev/null && echo $user is exist || { useradd $user; echo $user
is created; }
done
[root@centos8 ~]# bash create_user.sh hehe xixi haha
hehe is created
xixi is created
haha is created
變數引用 reference
[root@centos8 ~]#cat test.sh
#!/bin/bash
title=ceo
ceo=long
#宣告引用變數ref
declare -n ref=$title
[ -R ref ] && echo "reference" # [ -R var ] 是bash4.4新特性
echo ref=$ref
ceo=king
echo ref=$ref
[root@centos8 ~]# bash test.sh
reference
ref=long
ref=king