
Sway 的 exec 指令默认在用户主目录(如 /home/theo)下执行命令,而非脚本所在路径,导致相对路径(如 data.json)查找失败、程序静默退出——这是 Wayland 合成器环境下常见的路径陷阱。
sway 的 `exec` 指令默认在用户主目录(如 `/home/theo`)下执行命令,而非脚本所在路径,导致相对路径(如 `data.json`)查找失败、程序静默退出——这是 wayland 合成器环境下常见的路径陷阱。
在 Sway(及多数 Wayland 合成器)中,exec 和 bindsym ... exec 指令不会自动切换到脚本所在目录,而是继承 Sway 进程的当前工作目录(通常是用户家目录 $HOME)。这与你在终端中手动 cd 到项目目录后运行脚本的行为存在本质差异。
你的 Python 脚本中使用了相对路径 'data.json' 进行读写:
data_path = 'data.json'
# ...
def save_data(data):
with open('data.json', 'w') as file: # ← 此处是相对路径!
json.dump(data, file)
当通过终端执行时(例如 cd ~/Repos/volumebar-dunst && python main.py raise 10%),当前工作目录为 ~/Repos/volumebar-dunst,data.json 被正确创建/读取;
但当 Sway 执行:
bindsym XF86AudioRaiseVolume exec "/home/theo/Repos/volumebar-dunst/bin/python /home/theo/Repos/volumebar-dunst/main.py raise 10%"
Sway 实际是在 /home/theo 目录下调用该命令,此时脚本尝试读取 /home/theo/data.json —— 文件不存在,触发 data_exists() 中的初始化逻辑,但后续 save_data() 写入时可能因权限、路径或 JSON 序列化异常(如 return_data.strip() 在空输出时引发 AttributeError)导致未捕获崩溃,表现为“执行到 amixer 后静默退出”。
✅ 解决方案:显式指定工作目录
推荐在 bindsym exec 中使用 cd 切换路径后再执行,确保环境一致性:
# ✅ 正确:先 cd 到项目根目录,再运行脚本 bindsym XF86AudioRaiseVolume exec "cd /home/theo/Repos/volumebar-dunst && ./bin/python main.py raise 10%" bindsym XF86AudioLowerVolume exec "cd /home/theo/Repos/volumebar-dunst && ./bin/python main.py lower 10%" bindsym XF86AudioMute exec "cd /home/theo/Repos/volumebar-dunst && ./bin/python main.py mute"
⚠️ 注意事项:
- 确保 main.py 具有可执行权限:chmod +x ~/Repos/volumebar-dunst/main.py;
- 若使用自定义 Python 解释器(如 ./bin/python),请确认其路径在目标目录下有效;
- 更健壮的做法是在 Python 脚本内固化工作目录,避免依赖外部环境:
import os # 在 main() 开头或模块级添加: os.chdir(os.path.dirname(os.path.abspath(__file__)))
? 调试建议(快速验证)
在 bindsym 中临时添加日志,定位实际执行路径和错误:
bindsym XF86AudioRaiseVolume exec "cd /home/theo/Repos/volumebar-dunst && pwd >> /tmp/sway-exec.log 2>&1 && ./bin/python main.py raise 10% >> /tmp/sway-exec.log 2>&1"
然后查看 cat /tmp/sway-exec.log,即可确认工作目录与报错详情。
总结:Sway 的 exec 不是“以脚本为中心”,而是“以会话为中心”。掌握工作目录控制权,是实现可靠自动化脚本的第一步。










