含Unicode特殊字符的Bash输出传入Python触发UnicodeDecodeError求助
报错根因拆解
你遇到的解码报错是两个环节的问题叠加导致的:
- Shell端的
cut -c -65在locale未正确配置UTF-8时,会按字节长度而非字符长度截断字符串。你用到的音乐标题里,日文片假名、「【】」「☯」这类符号都是3字节存储的UTF-8字符,截断到第65字节位置时,刚好把完整的多字节字符从中间切开,生成了不合法的孤立字节(也就是报错里提到的0xe2),这也是单独运行Shell脚本时末尾出现乱码�的原因。 - Python端读取Shell输出时,默认对解码错误没有容错机制,遇到被截断的非法字节就会直接抛出
UnicodeDecodeError,没有做容错替换处理。
修复操作
1. 重构Shell脚本的输出逻辑
彻底去掉Shell端的截断操作,避免切坏多字节字符,修改后的可直接运行脚本:
player_status=$(playerctl status 2> /dev/null) if [[ $? -eq 0 ]]; then metadata="$(playerctl metadata title 2> /dev/null)" else metadata="No music playing" fi # 直接输出原始标题,不在Shell层做长度截断 echo "$metadata"
如果一定要在Shell层做截断,需要先在脚本开头加export LC_ALL=C.UTF-8强制启用UTF-8 locale,不然cut依然会按字节切坏多字节字符。
2. 重构Python端的Shell调用逻辑
替换原来的os.popen写法,改成支持指定编码、解码容错的调用方式,同时把截断逻辑移到Python层做,保证多字节字符不会被切坏:
import subprocess def getMusicName(): # 调用Shell脚本,关闭默认的严格解码 shell_run = subprocess.run( ["bash", "/home/nep/Self Script/now-playing.sh"], capture_output=True, encoding="utf-8", # 遇到非法截断的字节直接替换为通用替换符,不抛异常 errors="replace" ) # 去掉输出自带的换行符,再按需截断前65个字符 return shell_run.stdout.strip()[:65]
修改完成后:
- 不会再出现因为cut切坏多字节字符导致的编码报错
- 就算偶尔出现不合法的字节,也会自动替换成可显示的符号,不会中断程序
- 末尾的自带换行(也就是你看到的⏎标识)会被
.strip()自动清掉
内容的提问来源于stack exchange,提问作者SyntaxKills
相关产品推荐
相关产品推荐

