[我试图在启动时作为系统服务运行bash脚本,我正在使用Raspbian Buster Lite在Raspberry Pi 4上执行此操作。
如果我手动运行bash脚本./hls.sh
,我将能够执行bash脚本;如果我执行sudo service tv start
,我也能够运行该服务,但是tv.service似乎无法执行bash脚本。 hls.sh
启动时。我确实为服务和bash文件都授予了权限chmod 777
。
这里的任何帮助将不胜感激,我已经尝试解决这个问题一个月了。
Bash脚本
#!/bin/bash
/usr/bin/ffmpeg -reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_delay_max 2 -y -nostdin \
-hide_banner -loglevel fatal \
-i http://10.0.0.11:9981/stream/channelnumber/2 \
-vcodec copy -acodec copy -scodec copy -g 60 \
-fflags +genpts -user_agent HLS_delayer \
-metadata service_provider="TimeShift" \
-metadata service_name="TV 1" \
-f hls -hls_flags delete_segments \
-hls_time 60 \
-hls_list_size 480 \
-hls_wrap 481 \
-hls_segment_filename /home/pi/hls/1_%03d.ts /home/pi/hls/1_hls.m3u8
服务
[Unit]
Description=Timeshift TV
After=tvheadend.service
PartOf=tvheadend.service
Restart=always
[Service]
ExecStartPre=/bin/mkdir -p /home/pi/hls/
ExecStart=/home/pi/hls.sh 103 &
ExecStop=/bin/rm -rf /home/pi/hls
[Install]
WantedBy=default.target
重新启动后,通过systemctl status检查状态
● tv.service - Timeshift TV
Loaded: loaded (/etc/systemd/system/tv.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Mon 2020-05-18 05:36:40 BST; 45s ago
Process: 465 ExecStartPre=/bin/mkdir -p -m777 /home/pi/hls/ (code=exited, status=0/SUCCESS)
Process: 472 ExecStart=/home/pi/hls.sh 103 & (code=exited, status=1/FAILURE)
Main PID: 472 (code=exited, status=1/FAILURE)
May 18 05:36:39 tv3 systemd[1]: Starting Timeshift TV...
May 18 05:36:39 tv3 systemd[1]: Started Timeshift TV.
May 18 05:36:40 tv3 systemd[1]: tv.service: Main process exited, code=exited, status=1/FAILURE
May 18 05:36:40 tv3 systemd[1]: tv.service: Failed with result 'exit-code'.
此服务文件存在一些问题。我将在下面解决这些问题,然后显示最终解决方案。
/home
目录下。虽然可能有效,但不建议这样做。这样做可能会导致许多范围外的问题。而是考虑将脚本放置在/opt
,/srv
或/usr/local
下。restorecon -r
。这样可确保SELinux上下文被重置为其正确的值,而不是将新上下文与旧上下文混合。当SELinux处于强制模式时,这可以帮助解决权限被拒绝的错误。Restart=
指令位于Restart=
之下,而不是[Service]
之下,因此应将其移至该位置或完全删除。因为systemd有时是可以原谅的,所以它可能是无害的,但是[Unit]
是定义该指令的指令,而不是systemd.service。ExecStart=
。只需保留它,然后将其作为普通脚本运行即可。如果配置正确,Systemd将处理其余部分。ExecStart=
更改为&
。这将使systemd能够执行其正常的停止行为,即在被要求停止服务时向脚本发送ExecStop=
。停止完成后(优雅地或强制性地),ExecStop=
将运行。由于似乎在脚本运行后您正在使用它进行清理,因此应该进行更改。如果按原样保留,systemd将删除目录,然后等待脚本退出,由于未告知脚本,脚本将永远不会执行此操作,因此systemd将等待超时时间,然后再要求内核ExecStopPost=
脚本。绝对不理想。ExecStopPost=
下的一些额外指令将解决有关此服务应如何行为的一些假设。SIGTERM
—以便定义而不是假定。如果保留为默认值,它将成为ExecStopPost=
的主目录,如果保留为默认值,则为SIGKILL
。而是将其设置为脚本的位置,如果为[Service]
,则设置为WorkingDirectory=
。WorkingDirectory=
-这样脚本不会以默认用户User
身份运行。我建议/root
或您希望管理/tmp
执行的任何用户。这样可以防止在脚本运行时为其授予root特权,而PrivateTmp=true
则不需要。User=
—可以说这是最重要的,因为脚本是一次性运行的,成功后将退出;它不会守护到后台并继续以默认的User=
服务运行。应该将其设置为root
,以便systemd知道。它将退出的脚本视为服务成功运行,然后继续运行。nobody
-在大多数情况下,应启用此功能。仅在极少数情况下应禁用它。默认行为是禁用的。启用后,脚本尝试存储在ffmpeg
中的所有内容实际上将透明地存储在名为ffmpeg
的命名空间目录中,以防止与Type=
中的其他文件发生任何冲突。如果使用此选项,我将更改Type=
写入simple
,而不是管理脚本旁边的目录,从而使您可以完全删除oneshot
和PrivateTmp=
。PrivateTmp=
和/tmp
带有/tmp/systemd-private-xxxx-servicename.service-xxxxx/
前缀,这样,它们将以/tmp
的身份运行,而不是所定义的ffmpeg
可能不是root;根据您对目录的期望,此操作可能必要也可能不必要。有关更多信息,请参见/tmp
。ExecStartPre=
更改为ExecStopPost=
;更有可能应该为该目标运行该服务,而不是默认启动任何目标。ExecStartPre=
,我会改用适度的ExecStopPost=
。它只需要执行位(+
)。因此,没有其他理由,这是最终解决方案:
目录结构:
root
systemd.service Table 1. Special executable prefixesUser=
Shell脚本:
WantedBy=default.target
服务文件:
multi-user.target
chmod 777
系统状态输出:
chmod 755