Bash if else编写dwmbar歌曲元数据函数问题排查
dwmbar调用playerctl展示媒体信息的代码错误排查
问题现象
在Bash环境下为dwmbar编写媒体信息模块,调用playerctl获取歌曲元数据,预期逻辑为:无媒体播放器运行、无内容播放(即playerctl status返回No players found)时模块不展示媒体内容;有播放内容时展示格式化的艺术家、歌曲名信息。但前两版实现无论是否有播放器运行,都会始终打印歌曲元数据,不符合预期。
前两版代码的错误点
原发帖版本错误
mpd() { PS=$(2>/dev/null playerctl status) echo "$(date): ${PS}" >> debug.log if [[ ${PS} == "No players available" ]];then printf "^c$pink^ ^c$blue^$(playerctl metadata --format '{{ uc(artist) }}') " printf "^c$pink^$(playerctl metadata --format '{{ uc(title) }}')^c$blue^ " else printf " " exit 0 fi }
存在三个核心问题:
- 分支逻辑完全写反:将打印元数据的逻辑放在了“匹配到无播放器提示”的if分支中,有播放器运行的场景反而进入else分支输出空格,和预期逻辑完全颠倒
- 匹配文本错误:
playerctl无播放器时实际返回文本为No players found,代码中写的No players available和实际返回值不匹配,精确相等判断永远无法命中预期分支 - 函数内误用
exit:exit指令会直接终止整个Shell进程,在dwmbar的模块函数中调用会直接导致整个状态栏退出,函数内需要终止逻辑应该用return而非exit
第一次编辑后版本错误
mpd() { PS=$(2>/dev/null playerctl status) echo "$(date): ${PS}" >> debug.log if ! [[ "${PS}" =~ ".*No play.*" ]];then MD=$(2>/dev/null playerctl metadata --format '{{uc(artist) }}|{{uc(title)}}') TITLE=$(echo ${MD} | cut -d'|' -f 1) ARTIST=$(echo ${MD} | cut -d '|' -f 2) printf "^c$pink^ ^c$blue^${TITLE}" printf "^c$pink^${ARTIST}^c$blue^ " else printf " " exit 0 fi }
除了保留了原版本中函数内误用exit的问题外,存在两个核心错误:
- Bash正则匹配写法错误:Bash中使用
=~操作符做正则匹配时,右侧的正则表达式如果加双引号,所有正则元字符(比如.*)会被解析为普通字面字符,不再具备正则通配能力。代码中".*No play.*"被当成普通字符串匹配,永远无法和实际返回值匹配,导致! [[ 匹配 ]]的条件永远为真,无论是否有播放器都会执行打印元数据的逻辑,这就是该版本始终输出元数据的根本原因。 - 字段切割逻辑写反:
--format定义的输出顺序是artist在前、title在后,cut切割后把artist值赋值给了TITLE变量、title值赋值给了ARTIST变量,会导致展示时歌曲名和艺术家信息颠倒。
可正常运行的最终版本
该版本修复了上述所有问题:通过子串通配符匹配*"No players"*,不需要精确匹配完整提示文本,兼容不同版本playerctl的返回差异;分支逻辑符合预期,仅在有播放器时拉取元数据;去掉了会导致状态栏崩溃的exit调用。
mpd() { PS=$(2>/dev/null playerctl status) NP='No players' if [[ "$PS" == *"$NP"* ]]; then printf " " else printf "^c$pink^ ^c$blue^$(playerctl metadata --format '{{ uc(artist) }}') " printf "^c$pink^$(playerctl metadata --format '{{ uc(title) }}')^c$blue^ " fi }
内容的提问来源于stack exchange,提问作者2346254765
相关产品推荐
相关产品推荐

