实验1

实验1

尝试监视 3 个不同的文件夹并在其中一个发生更改时运行脚本。问题是脚本需要知道哪个文件夹发生了更改,而我似乎找不到方法来传递它。

[Path]
PathChanged=/x/y/z
PathChanged=/a/b/c
PathChanged=/foo/bar
Unit=123.service

[Install]
WantedBy=multi-user.target

我假设没有办法做到这一点。而且我需要要么有 3 个独立的 .path 文件(恶心),要么让脚本在每次其中一个文件夹发生变化时迭代所有 3 个文件夹(低效且恶心)。

但我想我应该在这里问。也许我缺少一个 systemd 变量,或者在没有 systemd 的情况下更有效的方法。那么有吗?

谢谢。

答案1

经过一番尝试后,我发现最简单的方法是每个路径使用一个*.path文件,并将每个路径模板化为一个*@.service文件。这是使用您的示例的内容:

$ systemctl --user cat 123* *.path
# /home/stew/.config/systemd/user/[email protected]
[Service]
Type=oneshot
ExecStart=/bin/echo %I

# /home/stew/.config/systemd/user/abc.path
[Path]
PathChanged=/a/b/c
[email protected]

# /home/stew/.config/systemd/user/foobar.path
[Path]
PathChanged=/foo/bar
[email protected]

# /home/stew/.config/systemd/user/xyz.path
[Path]
PathChanged=/x/y/z
[email protected]

可以*.service通过以下方式访问该路径%I 说明符

为了获取Unit=名称,我使用了systemd 转义:

$ systemd-escape [email protected] \
      '/x/y/z' \
      '/a/b/c' \
      '/foo/bar'
[email protected] [email protected] [email protected]

相关手册页:

如果您想知道是否有更简单的解决方案,以下是我尝试过的方法:


实验1

假设:它在环境变量中。

系统执行(5)给出环境变量的列表。有可能设置了类似$RUNTIME_DIRECTORYor 的东西。$LISTEN_FDS

实验设置:

$ mkdir /home/stew/systemdpath
$ systemctl --user cat simplepath.*
# /home/stew/.config/systemd/user/simplepath.path
[Unit]
Description=Path testing

[Path]
DirectoryNotEmpty=/home/stew/systemdpath

# /home/stew/.config/systemd/user/simplepath.service
[Unit]
Description=Path testing unit

[Service]
Type=oneshot
ExecStart=/usr/bin/env
$ systemctl --user start simplepath.path

实验结果:

$ touch ~/systemdpath/file
$ journalctl --user simplepath.service
Jul 28 08:26:16 stewbian systemd[31634]: Starting Path testing unit...
Jul 28 08:26:16 stewbian env[334512]: HOME=/home/stew
Jul 28 08:26:16 stewbian env[334512]: LANG=en_GB.UTF-8
Jul 28 08:26:16 stewbian env[334512]: LANGUAGE=en_GB:en
Jul 28 08:26:16 stewbian env[334512]: LOGNAME=stew
Jul 28 08:26:16 stewbian env[334512]: PATH=/home/stew/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
Jul 28 08:26:16 stewbian env[334512]: SHELL=/bin/bash
Jul 28 08:26:16 stewbian env[334512]: USER=stew
Jul 28 08:26:16 stewbian env[334512]: XDG_RUNTIME_DIR=/run/user/1000
Jul 28 08:26:16 stewbian env[334512]: GTK_MODULES=gail:atk-bridge
Jul 28 08:26:16 stewbian env[334512]: QT_ACCESSIBILITY=1
Jul 28 08:26:16 stewbian env[334512]: DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
Jul 28 08:26:16 stewbian env[334512]: DESKTOP_SESSION=/usr/share/xsessions/i3
Jul 28 08:26:16 stewbian env[334512]: DISPLAY=:0
Jul 28 08:26:16 stewbian env[334512]: GPG_AGENT_INFO=/run/user/1000/gnupg/S.gpg-agent:0:1
Jul 28 08:26:16 stewbian env[334512]: PAM_KWALLET5_LOGIN=/run/user/1000/kwallet5.socket
Jul 28 08:26:16 stewbian env[334512]: PWD=/home/stew
Jul 28 08:26:16 stewbian env[334512]: SHLVL=1
Jul 28 08:26:16 stewbian env[334512]: XAUTHORITY=/home/stew/.Xauthority
Jul 28 08:26:16 stewbian env[334512]: XDG_CURRENT_DESKTOP=i3
Jul 28 08:26:16 stewbian env[334512]: XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0
Jul 28 08:26:16 stewbian env[334512]: XDG_SESSION_CLASS=user
Jul 28 08:26:16 stewbian env[334512]: XDG_SESSION_DESKTOP=i3
Jul 28 08:26:16 stewbian env[334512]: XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session5
Jul 28 08:26:16 stewbian env[334512]: XDG_SESSION_TYPE=x11
Jul 28 08:26:16 stewbian env[334512]: _=/usr/bin/dbus-update-activation-environment
Jul 28 08:26:16 stewbian env[334512]: MANAGERPID=31634
Jul 28 08:26:16 stewbian env[334512]: INVOCATION_ID=837f6b2e56b543c9b51cda4ee8952fa8
Jul 28 08:26:16 stewbian env[334512]: JOURNAL_STREAM=8:21581980
Jul 28 08:26:16 stewbian systemd[31634]: simplepath.service: Succeeded.
Jul 28 08:26:16 stewbian systemd[31634]: Finished Path testing unit

结论:

Systemd 不会将路径放入环境变量中。


实验2

假设:可以模板化

考虑到$LISTEN_FDS套接字和路径之间有一些相似之处。套接字在以下情况下被模板化:Accept=yes已设置,那么如果我们尝试使用路径会怎么样?

初始设置:

$ systemctl --user cat simplepath*
# /home/stew/.config/systemd/user/simplepath.path
[Unit]
Description=Path testing

[Path]
DirectoryNotEmpty=/home/stew/systemdpath
[email protected]

# /home/stew/.config/systemd/user/[email protected]
[Unit]
Description=Path testing unit

[Service]
Type=oneshot
ExecStart=/bin/echo %i

实验结果:

$ systemctl --user start simplepath.path
$ touch ~/systemdpath/file
$ journalctl --user --since "5 minutes ago"
Jul 28 09:14:25 stewbian systemd[31634]: Starting Path testing unit...
Jul 28 09:14:25 stewbian echo[336171]: simplepath
Jul 28 09:14:25 stewbian systemd[31634]: [email protected]: Succeeded.

结论

服务中回显的实例是服务名称本身。那没有帮助。


实验3

假设:每个路径都可以有自己的文件和服务模板

实验设置:

$ mkdir ~/path1
$ mkdir ~/path2
$ systemctl --user cat path*
# /home/stew/.config/systemd/user/path1.path
[Unit]
Description=Path1 testing

[Path]
DirectoryNotEmpty=%h/path1
[email protected]

# /home/stew/.config/systemd/user/path2.path
[Unit]
Description=Path2 testing

[Path]
DirectoryNotEmpty=%h/path2
[email protected]

# /home/stew/.config/systemd/user/[email protected]
[Unit]
Description=Path testing unit

[Service]
Type=oneshot
ExecStart=/bin/echo %h/%i
$ systemctl --user start path1.path path2.path

实验:

$ touch ~/path1
$ touch ~/path2
$ journalctl --user --since "5 minutes ago"
Jul 28 09:43:45 stewbian systemd[31634]: Starting Path testing unit...
Jul 28 09:43:45 stewbian echo[336517]: /home/stew/path1
Jul 28 09:43:45 stewbian systemd[31634]: [email protected]: Succeeded.
Jul 28 09:43:45 stewbian systemd[31634]: Finished Path testing unit.
Jul 28 09:43:50 stewbian systemd[31634]: Starting Path testing unit...
Jul 28 09:43:50 stewbian echo[336519]: /home/stew/path2
Jul 28 09:43:50 stewbian systemd[31634]: [email protected]: Succeeded.
Jul 28 09:43:50 stewbian systemd[31634]: Finished Path testing unit.

结论

您可以让一个模板化服务单元适用于多个路径单元。这似乎是最简单的方法。

我在这里遇到的问题是该服务使用%h主目录。当我/在模板名称中 包含该字符时,我遇到了问题。systemd 转义(1)似乎可以帮助解决这个问题。

答案2

在引入 systemd 之前的某些 Linux 上(例如 RedHat 6.x),我们可以安装和使用 incrontab 命令,它比 systemd.path 解决方案更简单、更完整。Incrontab 和 incrond 为 inotify api 提供了一个强大的接口,但不幸的是,它被 systemd.path 取代了,与 incrontab 相比,它并不完整。我猜 incrontab 仍然可以安装在使用 systemd 的当前版本上,但它目前还没有得到维护,因此,它不适合生产或关键系统。我希望这个问题能在未来的版本中得到修复。

相关内容