數組

            數組所謂數組,是有序的元素序列。若將有限個類型相同的變量的集合命名,那麼這個名稱爲數組名。組成數組的各個變量稱爲數組的分量,也稱爲數組的元素,有時也稱爲下標變量。用於區分數組的各個元素的數字編號稱爲下標。數組是在程序設計中,爲了處理方便, 把具有相同類型的若干元素按無序的形式組織起來的一種形式。 這些無序排列的同類數據元素的集合稱爲數組。

             變量:存儲單個元素的內存空間 ;

             數組:存儲多個元素的連續的內存空間,相當於多個變量的 集合 

             數組名和索引:索引:編號從0開始,屬於數值索。注意:索引可支持使用自定義的格式,而不僅是數值格式 ,即爲關聯索引,bash4.0版本之後開始支持 。bash的數組支持稀疏格式(索引不連續)

            聲明數組: declare -a ARRAY_NAME

                              declare -A ARRAY_NAME: 關聯數組

                              注意:兩者不可相互轉換


declare命令用於聲明和顯示已存在的shell變量。

            declare -x varname 設置環境變量
            declare -i 聲明整數
            declare -g 設置函數爲全局函數
            declare -xf 設置環境函數
            declare -a 數組名 聲明索引數組
            declare -A 數組名 聲明關聯數組
            declare -a 查看所有索引數組
            declare -A 查看所有關係數組


 數組元素的賦值

         (1) 一次只賦值一個元素 ARRAY_NAME[INDEX]=VALUE 

                                              weekdays[0]="Sunday"

                                              weekdays[4]="Thursday"

[root@centos7 ~]# title[0]=boss
[root@centos7 ~]# title[1]=ceo
[root@centos7 ~]# title[2]=coo
[root@centos7 ~]# declare -a |grep title
declare -a title='([0]="boss" [1]="ceo" [2]="coo")'


        (2) 一次賦值全部元素 ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)

[root@centos7 ~]# name=(liubei guanyu zhangfei zhaoyun)
[root@centos7 ~]# declare -a |grep name                
declare -a name='([0]="liubei" [1]="guanyu" [2]="zhangfei" [3]="zhaoyun")'


        (3) 只賦值特定元素 ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)

[root@centos7 ~]# course=([0]=linux [2]=python [5]=oracle)
[root@centos7 ~]# declare -a |grep course
declare -a course='([0]="linux" [2]="python" [5]="oracle")'



          (4) 交互式數組值對賦值 read -a ARRAY

[root@centos7 ~]# read -a menu
niuroumian  caomian  jidanmian 
[root@centos7 ~]# declare -a |grep menu
declare -a menu='([0]="牛niuroumian" [1]="caomian" [2]="jidanmian")'

可以使用步進

[root@centos7 ~]# digit=({1..10})
[root@centos7 ~]# declare -a |grep digit
declare -a digit='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="7" [7]="8" [8]="9" [9]="10"

可以使用通配符

root@(6-1)zuoye# ser=(./*.sh
root@(6-1)zuoye# declare -a |grep ser
declare -a ser='([0]="./10.sh" [1]="./11.sh" [2]="./1.sh" [3]="./2.sh" [4]="./4.sh" [5]="./5.sh" [6]="./7.sh" [7]="./8.sh" [8]="./caipiao.sh" [9]="./dengyao-sjx.sh.sh" [10]="./hans.sh" [11]="./juxing.sh" [12]="./qipan.sh" [13]="./shuzi-sjx.sh" [14]="./suiji1.sh" [15]="./until.sh")'

顯示所有數組:declare  -a  (可以配合grep一起使用)

引用數組
            引用數組元素:

            ${ARRAY_NAME[INDEX]}

            注意:省略[INDEX]表示引用下標爲0的元素

[root@centos7 ~]# echo $digit  $數組名  #僅引用第一個值
1
[root@centos7 ~]# echo ${digit[1]}  #指定下標以引用指定值
3

引用數組所有元素: 數組後加“*”和“@”

            ${ARRAY_NAME[*]}

            ${ARRAY_NAME[@]}

root@(6-1)zuoye# echo ${ser[*]}
./10.sh ./11.sh ./1.sh ./2.sh ./4.sh ./5.sh ./7.sh ./8.sh ./caipiao.sh ./dengyao-sjx.sh.sh ./hans.sh ./juxing.sh ./qipan.sh ./shuzi-sjx.sh ./suiji1.sh ./until.sh
root@(6-1)zuoye# echo ${ser[@]}
./10.sh ./11.sh ./1.sh ./2.sh ./4.sh ./5.sh ./7.sh ./8.sh ./caipiao.sh ./dengyao-sjx.sh.sh ./hans.sh ./juxing.sh ./qipan.sh ./shuzi-sjx.sh ./suiji1.sh ./until.sh


數組的長度(數組中元素的個數):數組前加“#”

            ${#ARRAY_NAME[*]}

            ${#ARRAY_NAME[@]}

root@(6-1)zuoye# echo ${#ser[@]}
16
root@(6-1)zuoye# echo ${#ser[*]}
16

引用最後一個值
            ${ARRAY_NAME[$[${#ARRAY_NAME[@]}-1]]}

root@(6-1)zuoye# echo ${ser[$[${#ser[@]}-1]]}
./until.sh

練習:分別顯示每一個值,每個值換一行。

[root@centos7 ~]# echo ${test[@]}
hello hi good morning
test[0] is hello
test[1] is hi
test[2] is good
test[3] is morning


方式一:
#在終端輸入,同bash中
[root@centos7 ~]# for n in $(seq 0 $[${#testshuzu[*]}-1]);do
> echo testshuzu[$n] is ${testshuzu[$n]}
> done
testshuzu[0] is liubei
testshuzu[1] is guanyu
testshuzu[2] is zhaofei
testshuzu[3] is huangzhong
testshuzu[4] is zhaoyun

方式二:
#在腳本中編輯, 需要從新定義數組,
#!/bin/bash
ser=({1..10})   #從新定義一個數組
declare -a  |  grep ser #輸出數組中的變量值

or i in $(seq 0 $[${#ser[@]}-1] )  ;do  #取出 變量最後一個值,進行循環。
echo "ser [$i] is ${ser[$i]}"
done

方式二的輸出:
root@(6-1)zuoye# ./lin 
declare -a ser='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="7" [7]="8" [8]="9" [9]="10")'
ser [0] is 1
ser [1] is 2
ser [2] is 3
ser [3] is 4
ser [4] is 5
ser [5] is 6
ser [6] is 7
ser [7] is 8
ser [8] is 9
ser [9] is 10


在索引數組中加值,加到最後(最後一個值爲n-1,加一個值就是n-1+1,就等於n)

在索引數組中加值,加到最後
[root@centos7 ~]# testshuzu[${#testshuzu[*]}]=machao
[root@centos7 ~]# for n in $(seq 0 $[${#testshuzu[*]}-1]);do echo testshuzu[$n] is ${testshuzu[$n]}; done
testshuzu[0] is liubei
testshuzu[1] is guanyu
testshuzu[2] is zhaofei
testshuzu[3] is huangzhong
testshuzu[4] is zhaoyun
testshuzu[5] is machao


刪除數組中的某元素:導致稀疏格式

            unset ARRAY[INDEX]

root@(6-1)zuoye# unset ser[0]
root@(6-1)zuoye# declare -a |grep ser
declare -a ser='([1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="7" [7]="8" [8]="9" [9]="10")  #顯示結果只少了ser[0]


刪除整個數組:

              unset ARRAY

root@(6-1)zuoye# unset ser
root@(6-1)zuoye# declare -a |grep ser
root@(6-1)zuoye#     #數組整個刪除沒事顯示


數組數據處理
     引用數組中的元素:

                數組切片:${ARRAY[@]:offset:number}

                 offset: 要跳過的元素個數

                number: 要取出的元素個數

                取偏移量之後的所有元素

                                ${ARRAY[@]:offset}

[root@centos7 ~]# echo ${testshuzu[*]:1:3}
zhaofei weiyan zhaoyun
[root@centos7 ~]# echo ${testshuzu[*]:1}   跳過一個值,取到最後
zhaofei weiyan zhaoyun machao machao


    向數組中追加元素:

                ARRAY[${#ARRAY[*]}]=value

    關聯數組:

         兩種方式:
                一:先聲明,再賦值

                    declare -A ARRAY_NAME 

            
declare -A testshuzu
testshuzu=([zhugong]=liubei [erdi]=guanyu [sandi]=zhangfei)

             二:聲明,賦值一步到位

                      ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2‘...)

            
declare -A weiguo=([chengxiang]=caocao [junshi]=simayi [jiangju]=xiahoudun )

 注意:關聯數組必須先聲明再調用


寫一個腳本會生成一個名爲digit的數組包含10個隨機數,顯示數組的所有值,再顯示最大值,最小值。
$RANDOM 0-32767
./digit.sh
All digit are .....
Max is
Min is

方法1:
fun1() {
for (( i=0;i<10;i++ ));do
        a=$(echo $RANDOM)
        digit[$i]=$a
        echo ${digit[$i]}
done
}
                fun1 |sort -nr > /app/shuzul
cat /app/shuzul
m=$( cat /app/shuzul |head -1)
n=$( cat /app/shuzul |tail -1)
echo max=$m
echo min=$n
rm /app/shuzul -rf

方法2:

#!/bin/bash
declare -i min max
declare -a digit
for ((i=0;i<10;i++));do
        digit[$i]=$RANDOM
        [ $i -eq 0 ] && min=${digit[0]} && max=${digit[0]} && continue
        [ ${digit[$i]} -gt $max ] && max=${digit[$i]} && continue
        [ ${digit[$i]} -lt $min ] && min=${digit[$i]} && continue
done
echo All digit are ${digit[*]}
echo Max is $max
echo Min is $min

編寫腳本,定義一個數組,數組中的元素是/var/log目錄下所有以.log結尾的文件;統計出其下標爲偶數的文件中的行數之和

方法1:

#!/bin/bash
Sum=0
File=(/var/log/*.log)
for ((i=0;i<=$[${#File[*]}-1];i++));do
        if [ $[$i%2] -eq 0 ];then
                Line=$(cat ${File[$i]} | wc -l)
                Sum=$[$Sum+$Line]
        fi
done
echo $Sum

方法2:

declare -a logfiles=(/var/log/*.log)
echo All logfile name ${logfiles[*]}
i=0
linesum=0
while [ $i -lt ${#logfiles[*]} ];do
        [ $[i%2] -eq 0 ]&& fileline=$(cat ${logfiles[$i]} |wc -l ) && let linesum+=$fileline
        let i++
done
echo All lines are $linesum

字符串字符串切片

     ${#var}:返回字符串變量var的長度

echo ${#name} echo ${#name[1]} 
    顯示變量或數組的字符數
root@(6-1)zuoye# name=wang123
root@(6-1)zuoye# echo ${#name}
7
root@(6-1)zuoye# echo ${#name[1]}
0
root@(6-1)zuoye# echo $name
wang123

   ${var:offset}:返回字符串變量var中從第offset個字符後(不包括 第offset個字符)的字符開始,到最後的部分,offset的取值在0 到 ${#var}-1 之間(bash4.2後,允許爲負值)

root@(6-1)zuoye# echo ${name:2}   #從左邊跳過2個字符,取到最後
ng123

    ${var:offset:number}:返回字符串變量var中從第offset個字符後 (不包括第offset個字符)的字符開始,長度爲number的部分

root@(6-1)zuoye#  echo ${name:2:3} #從左邊跳過2個字符,取3個字符
ng1

    ${var: -length}:取字符串的最右側幾個字符

root@(6-1)zuoye# echo ${name: -2}   #從右向左取2個字符,注意冒號後至少打一個空格
23
     注意:冒號後必須有一空白字符

    ${var:offset:-length}:從最左側跳過offset字符,一直向右取到 距離最右側lengh個字符之前的內容

[root@centos7 ~]# echo ${name:3:-1} #從左邊跳過3個字符,從右邊跳過1個字符
r1

root@(6-1)zuoye# echo ${name: -3:1} #從右向左取3個字符,再從左向右取1個字符
1


     ${var: -length:-offset}:先從最右側向左取到length個字符開始 ,再向右取到距離最右側offset個字符之間的內容

name=qwer12
root@(6-1)zuoye# echo ${name:-3:-1}  #從右向左取3個字符,再從右向左去掉1個字符
r1
      注意:-length前空格


字符串處理

基於模式取子串

        ${var#*word}:其中word可以是指定的任意字符 功能:自左而右,查找var變量所存儲的字符串中,第一 次出現的word, 刪除字符串開頭至第一次出現word字符之間的 所有字符

從左至右查找
[root@centos7 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@centos7 ~]# echo ${PATH#*local}
/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

         ${var##*word}:同上,貪婪模式,不同的是,刪除的 是字符串開頭至最後一次由word指定的字符之間的所有內容

 示例:

        file="var/log/messages“

        ${file#*/}: log/messages

        ${file##*/}: messages

[root@centos7 ~]# echo ${PATH##*local}   貪婪模式
/bin:/usr/sbin:/usr/bin:/root/bin

${var%word*}:其中word可以是指定的任意字符;

         功能:自右而左,查找var變量所存儲的字符串中,第一 次出現的word, 刪除字符串最後一個字符向左至第一次出現 word字符之間的所有字符;

        file="/var/log/messages"

        ${file%/*}: /var/log

從左至右查找
[root@centos7 ~]# echo ${PATH} 
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@centos7 ~]# echo ${PATH%local*}
/usr/local/sbin:/usr/


${var%%word*}:同上,只不過刪除字符串最右側的字符向 左至最後一次出現word字符之間的所有字符;

[root@centos7 ~]# echo ${PATH%%local*}
/usr/

[root@centos7 ~]# url=http://www.magedu.com:8080
[root@centos7 ~]# echo ${url%%:*}
http
[root@centos7 ~]# echo ${url##*:}
8080
[root@centos7 ~]# url=http://www.magedu.com:8080
[root@centos7 ~]# echo ${url%%:*}
http
[root@centos7 ~]# echo ${url##*:}
8080

示例:

        url=http://www.magedu.com:80

        ${url##*:} 80

        ${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@centos7 ~]# name="Zhangfei LiuBeI"
[root@centos7 ~]# echo ${name,,}        
zhangfei liubei
[root@centos7 ~]# echo ${name^^}
ZHANGFEI LIUBEI


圖片.png

高級變量用法-有類型變量

Shell變量一般是無類型的,但是bash Shell提供了declare和 typeset兩個命令用於指定變量的類型,兩個命令是等價的

declare [選項] 變量名

    -r 聲明或顯示只讀變量

    -i 將變量定義爲整型數

    -a 將變量定義爲數組

    -A 將變量定義爲關聯數組

    -f 顯示已定義的所有函數名及其內容

    -F 僅顯示已定義的所有函數名

    -x 聲明或顯示環境變量和函數

    -l 聲明變量爲小寫字母 declare –l var=UPPER

    -u 聲明變量爲大寫字母 declare –u var=lower

eval命令

eval命令將會首先掃描命令行進行所有的置換,然後再執行該 命令。該命令適用於那些一次掃描無法實現其功能的變量.該 命令對變量進行兩次掃描

[root@centos7 ~]# mage=linux
[root@centos7 ~]# linux=centos
[root@centos7 ~]# eval echo \$$mage                    
centos

[root@centos7 ~]# centos=redhat

[root@centos7 ~]# eval echo \$$(eval echo \$$mage)     
redhat

[root@centos7 ~]# n=10
[root@centos7 ~]# echo {1..$n}
{1..10}
[root@centos7 ~]# eval echo {1..$n}
1 2 3 4 5 6 7 8 9 10

間接變量引用

如果第一個變量的值是第二個變量的名字,從第一個變量引 用第二個變量的值就稱爲間接變量引用

variable1的值是variable2,而variable2又是變量名, variable2的值爲value,間接變量引用是指通過variable1獲 得變量值value的行爲

        variable1=variable2

        variable2=value

bash Shell提供了兩種格式實現間接變量引用

        eval tempvar=\$$variable1

        tempvar=${!variable1}

[root@centos7 ~]# echo $mage
linux
[root@centos7 ~]# echo $linux
centos
[root@centos7 ~]# test=${!mage}
[root@centos7 ~]# echo $test
centos

創建臨時文件

    mktemp命令:創建並顯示臨時文件,可避免衝突

     mktemp [OPTION]... [TEMPLATE]

            TEMPLATE: filename.XXX

                    X至少要出現三個

    OPTION:

            -d: 創建臨時目錄

            -p DIR或--tmpdir=DIR:指明臨時文件所存放目錄位置

    示例:

mktemp /tmp/test.XXX
tmpdir=`mktemp –d /tmp/testdir.XXX`
mktemp --tmpdir=/testdir test.XXXXXX

安裝複製文件

    install命令:

            install [OPTION]... [-T] SOURCE DEST 單文件

            install [OPTION]... SOURCE... DIRECTORY

            install [OPTION]... -t DIRECTORY SOURCE...

            install [OPTION]... -d DIRECTORY...創建空目錄

    選項:

            -m MODE,默認755

            -o OWNER

            -g GROUP

示例:

install -m 700 -o wang -g admins srcfile desfile
install –m –d /testdir/installdir
install -m 700 -o liubei -g root /etc/passwd /app/hellopasswd

expect介紹

            expect 是由Don Libes基於Tcl( Tool Command Language )語言開發的,主要應用於自動化交互式操作的場景,藉助 Expect處理交互的命令,可以將交互過程如:ssh登錄,ftp 登錄等寫在一個腳本上,使之自動化完成。尤其適用於需要 對多臺服務器執行相同操作的環境中,可以大大提高系統管 理人員的工作效率

expect命令

expect 語法:

expect [選項] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]

選項

     -c:從命令行執行expect腳本,默認expect是交互地執行的

                示例:expect -c 'expect "\n" {send "pressed enter\n"}

     -d:可以輸出輸出調試信息

                示例:expect -d ssh.exp

expect中相關命令

    spawn:啓動新的進程

    send:用於向進程發送字符串 ,就是執行交互動作

    expect:從進程接收字符串

    interact:允許用戶交互

    exp_continue 匹配多個字符串在執行動作後加此命令

expect最常用的語法(tcl語言:模式-動作)

單一分支模式語法:

    expect "hi" {send "You said hi\n"}

root@(6-1)~# expect    #進入expect交互式模式
expect1.3> expect "hi" {send "You said hi\n"}   # expect 從進程接收字符串  , send:用於向進程發送字符串 ,
hi
You said hi
           匹配到hi後,會輸出“you said hi”,並換行

多分支模式語法:

    expect "hi" { send "You said hi\n" } \

    "hehe" { send “Hehe yourself\n" } \

    "bye" { send “Good bye\n" }

下圖中紅色標識爲接受發送詞彙,橙色標識爲匹配變量,和交互式輸出變量

圖片.png

匹配hi,hello,bye任意字符串時,執行相應輸出。等同如下:

    expect {

    "hi" { send "You said hi\n"}

    "hehe" { send "Hehe yourself\n"}

    "bye" { send “Good bye\n"

    }

   腳本實現免密碼登錄

方法一:

#!/usr/bin/expect
#time:2018.3.24
#edition:1.1
#effect:Interactive logon automatic input password(交互式登錄自動輸入密碼)
#expect格式開頭
#spawn新建進程,也就是ssh的連接
spawn  ssh [email protected]
#expect 從進程接收字符串 ,設置接收字符串
#send 向進程發送字符串,設置密碼...
#exp_continue,需要匹配的次數不止一次,所以需要在前邊,
#執行動作後加上exp_continue,以表示還有,後邊還有動作,沒有結束.
expect {
        "yes/no" { send "yes\n" ;exp_continue }
        "password" { send "centos\n" }
}
#interact允許用戶交互,無論值執不執行腳本任務,最後停留在目標終端上。
interact
#expect eof表示結束,登陸上去執行完腳本任務,直接退出,不在目標終端上停留
#expect eof
~

方式二:

設置變量方式實現

#!/usr/bin/expect
#time:2018.3.24
#edition:1.1
#effect:Interactive logon automatic input password(交互式登錄自動輸入密碼)
#設置三個變量
set user root  
set remotehost 172.18.250.249
set password centos
spawn ssh $user@$remotehost
expect {
        "yes/no" { send "yes\n" ;exp_continue }
        "password" { send "$password\n" }
}
interact
#expect eof

方法三:

執行登錄後的後續操作

設置三個位置變量來實現變量的賦值

#!/usr/bin/expect
#time:2018.3.24
#edition:1.1
#effect:Interactive logon automatic input password(交互式登錄自動輸入密碼)
#設置三個位置變量
set user [lindex $argv 0]
set remotehost [lindex $argv 1]
set password [lindex $argv 2]
spawn ssh $user@$remotehost
expect {
        "yes/no" { send "yes\n" ;exp_continue }
        "password" { send "$password\n" }
}
expect "]#" { send "useradd liubei\n" }
expect "]#" { send "echo redhat|passwd --stdin liubei\n" }
send "exit\n"
expect eof

方法四:
使用shell腳本格式

通過EOF實現賦值。

#!/bin/bash
#time:2018.3.24
#edition:1.1
#effect:Interactive logon automatic input password(交互式登錄自動輸入密碼)
user=$1
remotehost=$2
password=$3
expect << EOF
spawn ssh $user@$remotehost
expect {
        "yes/no" { send "yes\n" ;exp_continue }
        "password" { send "$password\n" }
}
expect "]#" { send "useradd liubei\n" }
expect "]#" { send "echo redhat|passwd --stdin liubei\n" }
send "exit\n"
expect eof
EOF

精簡的shell

#!/bin/bash
#time:2018.3.24
#edition:1.1
#effect:Interactive logon automatic input password(交互式登錄自動輸入密碼)
user=$1
remotehost=$2
password=$3
expect << EOF
spawn ssh $user@$remotehost
expect {
        "yes/no" { send "yes\n" ;exp_continue }
        "password" { send "$password\n" }
}
expect "]#" { send "useradd liubei\n" }
expect "]#" { send "id liubei" }
interact
EOF


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章