如何在NixOS中创建systemd服务模板?%u占位符未展开如何解决
问题原因
你遇到的%u不展开的问题核心是:NixOS提供的systemd.services.<name>.script是语法糖配置,它会自动将你写的脚本内容打包成一个存放在Nix Store中的独立shell脚本,再自动把ExecStart指向这个生成的脚本。而systemd的模板占位符(如%u、%i等)只会解析ExecStart行本身的内容,不会解析被调用的脚本内部的字符串,所以你写在script里的%u会作为静态文本保留,不会被展开。
规范解决方案
方案1:直接定义ExecStart(适合简单逻辑)
不需要使用script字段,直接在serviceConfig中定义ExecStart,让占位符直接出现在ExecStart行中,systemd就可以正常解析:
systemd.services."myuser@" = { serviceConfig = { Type = "oneshot"; # 直接把占位符写在ExecStart行内 ExecStart = "${pkgs.bash}/bin/bash -c 'echo Hi, %u'"; }; };
方案2:将占位符作为参数传给独立脚本(适合复杂逻辑)
如果你的服务逻辑比较复杂,不想都堆在ExecStart行里,可以先把逻辑写成独立脚本,再在ExecStart调用脚本时把占位符作为参数传入:
let # 先编写你的业务脚本,用位置变量接收参数 myServiceScript = pkgs.writeScriptBin "my-user-service" '' #!/${pkgs.bash}/bin/bash set -e # $1 对应传入的%u展开后的值 echo Hi, $1 # 其他复杂逻辑写在这里 ''; in { systemd.services."myuser@" = { serviceConfig = { Type = "oneshot"; # 调用脚本时传入systemd占位符,由systemd完成展开后再传给脚本 ExecStart = "${myServiceScript}/bin/my-user-service %u"; }; }; }
补充说明
systemd模板服务常用的占位符可以按需选择:
%i:模板实例名,即@后面的字符串,比如myuser@foo.service中%i的值为foo%u:服务运行的用户的用户名%h:服务运行的用户的家目录路径
内容的提问来源于stack exchange,提问作者l0b0
相关产品推荐
相关产品推荐

