Bash脚本遍历pacmd输出索引时echo莫名打印目录文件名问题
异常根因
这是Shell无引号变量展开的默认规则导致的,和echo命令本身无关:
- 你直接在终端执行
pacmd list-sinks | grep "index:"得到的输出里,开头的*是pacmd输出自带的标记——用来标识当前正在使用的默认音频设备,这个符号恰好是Shell可识别的文件名通配符。 - 脚本中将命令结果存入
sinks_index变量后,循环内写echo $i时没有给变量加双引号,Shell在执行echo前会对变量值自动做两步处理:- 第一步做单词分割:把所有空白(空格、换行、制表符)作为分隔符,把整段字符串拆成独立词元,其中一个词元就是单独的
* - 第二步做通配符展开:如果词元包含
*/?/[]这类通配符,Shell会将其替换为当前工作目录下匹配规则的文件名。单独的*会匹配当前目录下所有非隐藏文件,你输出里的audio_name_switcher.sh/audio.py等文件名,就是这一步被自动展开出来的。
- 第一步做单词分割:把所有空白(空格、换行、制表符)作为分隔符,把整段字符串拆成独立词元,其中一个词元就是单独的
- 后续拆分出的
index:、1、2、3等词元不含通配符,不会被替换,直接传给echo就原样打印出来,和你看到的后半段输出完全对应。
修复方案
Shell脚本编写的通用准则:除了明确需要触发通配符展开、单词分割的场景外,所有变量展开必须用双引号包裹,避免触发不必要的解析逻辑,同时建议用$()替代老旧的反引号做命令替换,可读性和兼容性更好。
如果你的需求是按空白拆分遍历命令输出的每个词,只需要在循环内引用变量时加双引号即可避免通配符展开,参考代码:
sinks_index=$(pacmd list-sinks | grep "index:") for i in $sinks_index do echo "$i" done
如果你的需求是逐行遍历grep的匹配结果,更稳妥的写法是用while read循环,从根源避免特殊字符解析异常:
pacmd list-sinks | grep "index:" | while read -r line do echo "$line" done
内容的提问来源于stack exchange,提问作者RootOfMinusOne
相关产品推荐
相关产品推荐

