以下脚本并不完整,只是抽取的部分进行 问题讲解。。
# @brief:dynamically maintaining and updating the hostMap-
# if add a cd_burner, so add it's info to hostMap.
# @return:if check a change, so return 1, or return 0.
function updateHostmap()
{
# check if the tag file exists.
# If it does, it indicates that the `enableSpecDriver`` in another terminal has not been completed;
# so directly return...
if [ -e ${BURN_FLAG_FILE} ];then
echo "[DEBUG] tag-flag-file not write finish."
return
fi
# is need to update the HOST_MAPFILE?
isUpdateMapfile=0
# assuming a computer has BURNER_COUNT CD-drivers
srcArray=() # like srN...
for index in $(seq 0 ${BURNER_COUNT})
do
ch=$(printf "%c" $(expr $index+48))
path="sr${ch}"
srcArray+=(${path})
done
for srName in "${srcArray[@]}" # srN
do
if [ -e "/dev/${srName}" ]; then # /dev/srN
# to get id_serial
# if the burner contains a light-disk, The process of transitioning from disable -> enable,
# it may take some time to load device information...
while true
do
res=`udevadm info "/dev/${srName}" |grep ID_SERIAL=`
regex="ID_SERIAL=(.*)"
if [[ ${res} =~ $regex ]]; then
idd_serial=${BASH_REMATCH[1]}
fi
if [ ! -z ${idd_serial} ];then
echo "[DEBUG] detect a new device or enable device, and it's id_serial is [${idd_serial}]."
break
else
echo "[DEBUG] detect a new device or enable device, but it has no id_serial. so, after sleep 3, obtain it again until it's id_seril not empty."
sleep 3 # length(idd_serial)=0
fi
done
# first, determine whether the detected id_serial of the burner exists in array ENABLE_BURNER_ARRAY???
# if so, this device is currently enabled and cannot be added as a new device for updates...
### call...
unset ENABLE_BURNER_ARRAY[@]
readEnableFile
if [ ${#ENABLE_BURNER_ARRAY[@]} -eq 0 ]; then
echo "[DEBUG] ENABLE_BURNER_ARRAY is empty."
else
echo "[DEBUG] ENABLE_BURNER_ARRAY value is:> ${ENABLE_BURNER_ARRAY[@]}"
fi
isContinue=1
for item_id in "${ENABLE_BURNER_ARRAY[@]}"
do
if [ "$item_id" = "$idd_serial" ];then
isContinue=0
continue
fi
done
if [ $isContinue -eq 0 ];then
continue
fi
### plugging and unplugging...
# [1]. it's a new device, so add a item to hostMap
# [2]. not a new device, and this device has alreay in our hostMap(plugging and unplugging of `the same device`)
# so update it's host in hostMap(Once the device is unplugged, it's host will change)
devPath=$(ls -l /sys/block |grep ${srName})
regex="/host([0-9]+)/"
if [[ $devPath =~ $regex ]] && [ ! -z ${idd_serial} ]; then
hostName="host${BASH_REMATCH[1]}"
hostMap["${idd_serial}"]=${hostName} # like host["HL-DT-ST_DVDRAM_GUD1N_KYJL590433"]="host2"
isUpdateMapfile=1
fi
# if a recording machine like XIN-KE that contains a robotic arm,
# /dev/srN is required during zero return initialization,
# or the door will eject back and forth...
is_shouldDelay=0
for vendor in "${VENDORS[@]}"
do
if [[ "$res" == *"$vendor"* ]];then
is_shouldDelay=1
break
fi
done
if [ $is_shouldDelay -eq 1 ];then
echo "[DEBUG] find all-in-one machine, delay for $ZERO_WAIT_TIME seconds to complete the zero return operation."
sleep $ZERO_WAIT_TIME
fi
# then disable the scanned /dev/srN
echo 0 > /sys/block/${srName}/device/delete
echo "[DEBUG] detect a new device /dev/${srName}, so disable it... "
fi
done
if [ ${isUpdateMapfile} -eq 1 ]; then
return 1
else
return 0
fi
}
片段分析
while true
do
res=`udevadm info "/dev/${srName}" |grep ID_SERIAL=`
regex="ID_SERIAL=(.*)"
if [[ ${res} =~ $regex ]]; then
idd_serial=${BASH_REMATCH[1]}
fi
if [ ! -z ${idd_serial} ];then
echo "[DEBUG] detect a new device or enable device, and it's id_serial is [${idd_serial}]."
break
else
echo "[DEBUG] detect a new device or enable device, but it has no id_serial. so, after sleep 3, obtain it again until it's id_seril not empty."
sleep 3 # length(idd_serial)=0
fi
done
主要留意idd_serial,实际这是一个全局变量,在函数外依然可以被正常访问。
上述逻辑主要是通过udevadm来提取 /dev/srN对应的 ID_SERIAL,
PC端共存在/dev/sr0和/dev/sr1两个光驱驱动。
首先,我们删除/dev/sr0和/dev/sr1,,,,,
然后重新扫描,是之前/dev/sr0所对应的设备被重新扫描出来,,,,
此时,将产生/dev/sr0,其会被我们的updateHostmap函数所捕获,并且idd_serial肯定会被赋值,即不为空。
后来再次将刚刚的/dev/sr0删除, 接着去扫描之前删除的/dev/sr1所对应的设备,被扫描后的该设备重新对应于/dev/sr0。
此时仍然会被updateHostmap所捕获。。。。。。。。。。。。。。
十分注意:执行 res=udevadm info "/dev/${srName}" |grep ID_SERIAL=
可能会返回空(因为/dev/sr0可能没有被加载完毕,,,),因为idd_serial之前已经被赋值了,,,所以流程会一直往下走,但是很明显,此时的这个idd_serial并不是我们想要的,它并不是重新被扫描后的设备对应的id_serial,,,,,而是一开始禁用后又启用的设备的id_serial。
于是,后面的逻辑就会因为idd_serial的错误值 而产生 差错。。。
导致后续的流程出现逻辑差错。。。。
解决方案
:
可以在函数中通关 local
关键字 进行修饰,将其 idd_serial修饰为局部变量。。。提醒:今后,为了避免这些问题,直接一律在函数中的变量全部声明为局部变量。
文章来源:https://www.toymoban.com/news/detail-524513.html
...
local idd_serial
...
当然还有其他一些解决方案
:
例如:可以
对 res=udevadm info "/dev/${srName}" |grep ID_SERIAL=
执行
的结果进行输出,,通过$?
是否等于0来判断上述命令是否执行成功,如果$?
返回1,表示失败,那就在继续获取,直到成功。。
另外,也可以
在idd_serial被使用完后,在函数内部的最下面给其赋值为空,,,,也是可以的。。。
但是,,,以上两种做法都不好,,,通过local来控制是最完美的方案。。。。文章来源地址https://www.toymoban.com/news/detail-524513.html
到了这里,关于关于shell中的一个命名引起的问题,局部变量的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!