Bash

函式名稱作為循環中的變數

  • July 28, 2016

概述:我將變數保存在配置文件中,稍後再呼叫它們。

每個名為 FailOverVM 的條目旁邊都有一個數字,例如 FailOverVM1,我想檢查它是否有數據並生成一個名為 FailOverVM1() 的函式,該函式稍後在腳本中啟動 $FailOverVM1Name,恰好是“Plex Server”

我可以像 StartVM1() 一樣手動完成它並且我可以工作,但我可能會在以後擴展到 15 個並希望它進行相應的調整。

為了澄清,我可以稍後使用 Case 語句啟動 VM,但我不能圍繞本身就是一個變數的變數。我希望我沒有混淆任何人。也許我讓這種方式比它現在或需要的更複雜。

#!/bin/bash
. "${BASH_SOURCE%/*}/configlocation.conf"
. $Configuration
checkVM1=$(nc -vvz $FailOverVM1IP $FailOverVM1Port 2>&1)
VMCount=$(grep "FailOverVM.Name" /media/VirtualMachines/Current/Configuration.conf | wc -l)
pinggateway=$(ping -q -w 1 -c 1 `ip r | grep default | cut -d ' ' -f 3` > /dev/null && echo ok || echo error = error)
STATE="error";

while [  $STATE == "error" ]; do
   #do a ping and check that its not a default message or change to grep for something else
   STATE=$(ping -q -w 1 -c 1 `ip r | grep default | cut -d ' ' -f 3` > /dev/null && echo ok || echo error)

   #sleep for 2 seconds and try again
   sleep 2
done

for i $VMCount; do
if [ -z "$FailOverVM$VMCountName" ];
   echo "$FailOverVM$VMCountName"
fi
done

StartVM1(){
 if [[ $checkVM1 = "Connection to $FailOverVM1IP $FailOverVM1Port port [tcp/*] succeeded!" ]]; then
   echo '$FailOverVM1Name is up'
 else
  echo "$FailOverVM1Name down"
  su -c 'VBoxManage startvm $FailOverVM1Name -type headless' vbox
 fi
}

到目前為止我在測試腳本中的進展情況

#!/bin/bash
. "${BASH_SOURCE%/*}/configlocation.conf"
. $Configuration
Pre='$FailOverVM'
post="FailOverVM"
name="Name"
VMCount=$(grep "FailOverVM.Name" $Configuration | wc -l) #Count entires in config file wirn FailOverVM*Name
while [[ $i -le $VMCount ]]
do
#if [ -z $Pre$i"Name" ];then #If the variable $FailOverVM*Name is not blank
  $post$i=$Pre$i$Name
  echo "$post$i" #print it
#else
#    echo $Pre$i"Name" "was empty"
#fi
   ((i = i + 1))
done

輸出:

./net2.sh: line 11: FailOverVM=$FailOverVM: command not found
FailOverVM
./net2.sh: line 11: FailOverVM1=$FailOverVM1: command not found
FailOverVM1
./net2.sh: line 11: FailOverVM2=$FailOverVM2: command not found
FailOverVM2
./net2.sh: line 11: FailOverVM3=$FailOverVM3: command not found
FailOverVM3
./net2.sh: line 11: FailOverVM4=$FailOverVM4: command not found
FailOverVM4
./net2.sh: line 11: FailOverVM5=$FailOverVM5: command not found
FailOverVM5
./net2.sh: line 11: FailOverVM6=$FailOverVM6: command not found
FailOverVM6

這裡的問題是沒有 $ FailOverVM without a number beside it, and what is up with “command not found FailOverVM5” (or any other number) I didn’t know I issued one. But the biggest problem is its not grabbing the variable $ FailOVerVM* 形成配置文件。我需要它用於 func 循環。



帶有@dave_thompson_085 幫助的新修改腳本

#!/bin/bash
. "${BASH_SOURCE%/*}/configlocation.conf"
. $Configuration
for i in ${!FailOverName[@]}; do 
 selip=FailOverIP[${i}]
 selport=FailOverPort[${i}]
 checkVM[$i]=$(nc -vvz ${!selip} ${!selport} 2>/devnull)
 echo ${!selip}
 echo ${!selport}
 echo FailOverName[${i}]
done

StartVM() { # first argument to a function is accessed as $1 or ${1}
 selname=FailOverName[${i}]
 if [[ checkVM[$i] =~ 'succeeded' ]]; then # only need to check the part that matters
   echo number $i name ${!selname} already up 
 else 
   echo starting number $i name ${!selname}
   echo su -c "VboxManager startvm '${!selname}' -headless" vbox # note " because ' $
 fi
}
#done
StartVM 1 # and 
StartVM 2 # etc

輸出

root@6120:~/.scripts# ./net2.sh -v
192.168.1.6
32400
FailOverName[1]
192.168.1.5
80
FailOverName[2]
192.168.1.7
80
FailOverName[3]
192.168.1.1
1030
FailOverName[4]
starting number 4 name finch
su -c VboxManager startvm 'finch' -headless vbox
starting number 4 name finch
su -c VboxManager startvm 'finch' -headless vbox
root@6120:~/.scripts# 

配置文件

#
FailOverVM1IP='192.168.1.6'
FailOverVM1Port='32400'
FailOverVM1Name='Plex Server'
FailOverVM1NASHDD='/media/VirtualMachines/Current/Plex\ Server/Plex\ Server.vmdk'
FailOverVM1LocalHDD='/home/vbox/VirtualBox\ VMs/Plex\ Server/Plex\ Server.vmdk'

FailOverVM2IP='192.168.1.7'
FailOverVM2Port='32402'
FailOverVM1Name='Plex Server2'
FailOverVM2NASHDD='/media/VirtualMachines/Current/Plex\ Server/Plex\ Server.vmdk'
FailOverVM2LocalHDD='/home/vbox/VirtualBox\ VMs/Plex\ Server/Plex\ Server.vmdk'

FailOverVM3IP='192.168.1.8'
FailOverVM3Port='32403'
FailOverVM3Name='Plex Server3'
FailOverVM3NASHDD='/media/VirtualMachines/Current/Plex\ Server/Plex\ Server.vmdk'
FailOverVM3LocalHDD='/home/vbox/VirtualBox\ VMs/Plex\ Server/Plex\ Server.vmdk'

FailOverVM4IP='192.168.1.9'
FailOverVM4Port='32404'
FailOverVM4Name='Plex Server4'
FailOverVM4NASHDD='/media/VirtualMachines/Current/Plex\ Server/Plex\ Server.vmdk'
FailOverVM4LocalHDD='/home/vbox/VirtualBox\ VMs/Plex\ Server/Plex\ Server.vmdk'

FailOverVM5IP='192.168.1.10'
FailOverVM5Port='32405'
FailOverVM5Name='Plex Server5'
FailOverVM5NASHDD='/media/VirtualMachines/Current/Plex\ Server/Plex\ Server.vmdk'
FailOverVM5LocalHDD='/home/vbox/VirtualBox\ VMs/Plex\ Server/Plex\ Server.vmdk'

FailOverIP[1]=192.168.1.6 FailOverName[1]=robin FailOverPort[1]=32400
FailOverIP[2]=192.168.1.5 FailOverName[2]=bluejay FailOverPort[2]=80
FailOverIP[3]=192.168.1.7 FailOverName[3]=sparrow FailOverPort[3]=80
FailOverIP[4]=192.168.1.1 FailOverName[4]=finch FailOverPort[4]=1030

VM1LogDirLogDir='/media/VirtualMachines/Logs/Plextstart'


PlexServerIP='192.168.1.6'
PlexPort='32400'
mydate=`date '+%Y-%m-%d_%H%M'`
rsyncfrom=
NASPlexvmHDD='/media/VirtualMachines/Current/Plex\ Server/Plex\ Server.vmdk'
LocalPlexvmDHDD='/home/vbox/VirtualBox\ VMs/Plex\ Server/Plex\ Server.vmdk'


PlexVMname='Plex Server'
PlexStartLogDir='/media/VirtualMachines/Logs/Plextstart'
RouterIp='192.168.1.1'

所以它會看到所有的虛擬機,但只執行最後一次和兩次。



#!/bin/bash
. "${BASH_SOURCE%/*}/configlocation.conf"
. $Configuration
for i in ${!FailOverName[@]}; do 
 selip=FailOverIP[${i}]
 selport=FailOverPort[${i}]
 checkVM[$i]=$(nc -vvz ${!selip} ${!selport} 2>&1)
 echo ${!selip}
 echo ${!selport}
 #echo ${i}
#done

StartVM() { # first argument to a function is accessed as $1 or ${1}
 selname=FailOverName[${i}]
 if [[ $checkVM[$i] =~ 'succeeded' ]]; then # only need to check the part that matters
   echo number $i name ${!selname} already up 
 else 
   echo starting number $i name ${!selname}
   echo su -c "VboxManager startvm '${!selname}' -headless" vbox # note " because ' prevents the variable expansion
 fi
}
StartVM
done

注意:檢查 VM 是否已經在執行還不起作用,但這不是我問的問題,所以這符合標準。

旁白:您可以wc -l通過使用grep -c FailoverVM.Name configfile.

但是,如果您想使用超過 9 位十進制的數字(例如 123456789abcdef),您的模式需要處於擴展模式FailoverVM[0-9][0-9]?NameFailoverVM[0-9]{1,2}Name處於-E擴展模式。

也是for i $VMCount語法錯誤;我假設你的意思是for i in $(seq $VMCount)


您可以在 bash 中使用(bang) 和另一個包含名稱的變數間接讀取變數:!

for i in $(seq $VMCount); do
 selname=FailoverVM${i}Name
 selip=FailoverVM${i}IP
 selport=FailoverVM${i}Port
 echo name ${!selname} is IP ${!selip} and port ${!selport}
done

這與其說是一個大笨蛋,eval但仍然很笨拙。但是您不能以這種方式設置變數,因此您應該為此使用數組。而且您不能對函式執行此操作,因此請編寫一個接受參數的函式來告訴它要使用哪個(一組)變數:

for i in $(seq $VMCount); do 
 selip-Failover${i}IP
 selport=Failover${i}Port
 checkVM[$i]=$(nc -vvz ${!selip} ${!selport} 2>/devnull)
}
StartVM() { # first argument to a function is accessed as $1 or ${1}
 selname=FailoverVM${1}Name
 if [[ checkVM[$1] =~ 'succeeded' ]]
 # only need to check the part that matters
 then echo number $1 name ${!selname} already up 
 else echo starting number $1
   su -c "VboxManager startvm ${!selname} -headless" vbox
 # note " because ' prevents the variable expansion
 fi
]
...
StartVM 1 # and 
StartVM 2 # etc

OTOH,如果您可以更改配置以對此類所有內容使用數組變數

FailoverIP[1]=10.255.1.1 FailoverName[1]=robin
FailoverIP[2]=10.255.2.2 FailoverName[2]=bluejay
etc

這將使一切變得更簡單。然後你不需要重新 grep 文件來計算條目,你可以使案例如${#FailoverName[@]}

引用自:https://unix.stackexchange.com/questions/298540