Bash脚本中将FC磁带驱动器路径每行输出存入独立变量的报错问题
问题分析
你遇到了两个核心问题:一是动态变量赋值的语法错误,二是管道创建子shell导致变量无法在循环外访问。
先看语法错误:${!var} 是bash中用来读取间接变量值的语法(比如如果var=foo,${!var}就等于$foo),但不能直接用它来赋值。你写的${!var}=$(...)会被bash解析成执行=/dev/st0这个“命令”,自然就报错了。
另外,你用管道| while read...的写法,while循环是运行在子shell中的,哪怕赋值成功,循环结束后父shell也看不到这些变量,这也是一个容易忽略的隐藏坑。
修复方案1:正确的动态变量赋值(解决语法+子shell问题)
我们可以用declare来实现动态变量赋值,同时用**进程替换(process substitution)**代替管道,避免子shell:
#!/bin/bash i=0 # 用< <(command)让while在当前shell执行,避免子shell while read line ; do var="path_tape$i" # 使用declare完成动态变量赋值 declare "$var=$(echo "$line" | awk '{print $4}')" ((i++)) done < <(/usr/bin/lsscsi --transport | grep fc: | grep tape) # 测试变量是否可用 echo "第一个驱动器路径:$path_tape0" echo "第二个驱动器路径:$path_tape1"
更推荐的方案2:使用bash数组(更简洁易维护)
其实处理多个同类路径时,bash数组比动态命名的变量更合适——不需要手动计数,遍历和访问都更方便:
#!/bin/bash # 用mapfile直接把命令的每行输出存入数组 mapfile -t drive_array < <(/usr/bin/lsscsi --transport | grep fc: | grep tape | awk '{print $4}') # 访问单个元素 echo "第一个驱动器:${drive_array[0]}" echo "第二个驱动器:${drive_array[1]}" # 遍历所有驱动器 echo "所有找到的磁带驱动器:" for drive in "${drive_array[@]}"; do echo "- $drive" done
mapfile -t会把命令输出的每一行(自动去掉换行符)依次存入数组drive_array,索引从0开始。如果你的bash版本较旧(低于4.0),可以用read循环手动填充数组:
#!/bin/bash drive_array=() while read -r path; do drive_array+=("$path") done < <(/usr/bin/lsscsi --transport | grep fc: | grep tape | awk '{print $4}')
额外优化:简化命令链
你原来的命令链lsscsi --transport | grep fc: | grep tape | awk...可以简化成单个awk命令,减少管道开销:
/usr/bin/lsscsi --transport | awk '/fc:/ && /tape/ {print $4}'
把这个替换到上面的脚本里,会更高效。
内容的提问来源于stack exchange,提问作者Yves C.
相关产品推荐
相关产品推荐

