요청 시 프로그램을 실행하기 위한 시스템 스크립트를 만들고 있습니다. 실행하면 작업 디렉토리가 존재하지 않을 수 있습니다. 따라서 이 디렉터리를 스크립트의 일부로 만들고 싶습니다. 그러나 지정된 작업 디렉터리가 존재하지 않기 때문에 오류가 발생합니다.
[Service]
User=Inplant
Group=Inplant
ExecStartPre=/bin/mkdir -p /home/inplant/IPSdevice/JAI1
WorkingDirectory=~/IPSdevice/JAI1
ExecStart=~/IPSdevice JAI1
시스템 스크립트의 일부로 작업 디렉토리를 생성하는 방법이 있습니까? 다음과 같은 프로그램을 실행하고 싶습니다.
mkdir ~/IPSdevice/JAI1; cd ~/IPSdevice/JAI1; ~/IPSdevice JAI1
물결표를 경로로 변경하여 첫 번째 문제를 해결할 수 있었습니다. 이제 다른 문제가 생겼습니다.
Aug 06 09:48:53 ubuntu systemd[1]: Started JAI Device Service.
-- Subject: Unit app-ips-jai1.service has finished start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit app-ips-jai1.service has finished starting up.
--
-- The start-up result is done.
Aug 06 09:48:53 ubuntu systemd[103782]: app-ips-jai1.service: Failed at step CHDIR spawning /home/inplant/IPSdevice/IPSdevice: No such file or directory
-- Subject: Process /home/inplant/IPSdevice/IPSdevice could not be executed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- The process /home/inplant/IPSdevice/IPSdevice could not be executed and failed.
--
-- The error number returned by this process is 2.
시스템 스크립트는 다음과 같습니다.
[Unit]
Description=JAI Device Service
# When systemd stops or restarts the app.service, the action is propagated to this unit
PartOf=app.service
# Start this unit after the app.service start
After=app-ips.service
[Service]
# Pretend that the component is running
RuntimeDirectory=IPS-JAI1
User=inplant
Group=inplant
ExecStartPre=mkdir -p /home/inplant/IPSdevice/JAI1
WorkingDirectory=/home/inplant/IPSdevice/JAI1
#ExecStart=/home/inplant/IPSdevice JAI1 > /dev/nul 2>&1 & echo $! > /var/run/jai1.pid
ExecStart=/home/inplant/IPSdevice/IPSdevice JAI1
# Restart the service on non-zero exit code when terminated by a signal other than SIGHUP, SIGINT, SIGTERM or SIGPIPE
#Restart=on-failure
[Install]
# This unit should start when app.service is starting
WantedBy=app-ips.service
일반적으로 "inplant" 사용자로 로그인하고 다음 명령을 실행하여 서비스를 시작합니다.
cd ~/IPSdevice
mkdir -p JAI
cd JAI
../IPSdevice JAI
답변1
문제의 일부는 ~
확장되지 않는 systemd를 사용하고 ~
있으므로 ~user
명령에 전체 경로를 지정해야 한다는 것입니다.
또한 systemd가 명령을 실행하기 전에 확인 하기 때문에 실제로 디렉터리를 만든 ExecStartPre=
다음 사용할 수 없습니다 . (실제로 모든 명령은 동일한 디렉터리에서 실행됩니다.)WorkingDirectory=
WorkingDirectory=
ExecStartPre=
이를 달성하려면 쉘 스크립트를 사용하여 ExecStart=
환경과 exec
데몬을 준비하십시오.
예를 들어 다음을 하나 생성합니다 /home/inplant/start_inplant.sh
.
#!/bin/sh
set -eu
mkdir -p /home/inplant/IPSdevice/"$1"
cd /home/inplant/IPSdevice/"$1"
exec /home/inplant/IPSdevice/IPSdevice "$1"
유닛 파일에서 다음을 사용하십시오.
[제공하다] 런타임 디렉터리=IPS-JAI1 사용자=생체 내 그룹=임플란트 환경=LD_LIBRARY_PATH=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib:/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam/bin/Linux64_x64:/opt/xview2_64/lib/:/opt/GO_SDK/lib /linux_x64 환경=GENICAM_ROOT_V3_0=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam ExecStart=/home/inplant/start_inplant.sh JAI1 # SIGHUP, SIGINT, SIGTERM 또는 SIGPIPE 이외의 신호에 의해 종료되면 0이 아닌 종료 코드로 서비스를 다시 시작합니다. 다시 시작 = 실패 시
필요하지 않거나 WorkingDirectory=
단위 ExecStartPre=
파일에 없습니다. 쉘 스크립트 자체에서 환경 변수를 내보내도록 결정할 수도 있으며, 둘 중 하나를 선호하는지 여부는 사용자에게 달려 있습니다.
중요한 부분은 사용하는 것입니다exec
쉘 스크립트에서. 이로 인해 쉘은 자신을 실행 프로그램으로 대체하여 프로그램은 쉘이 시작될 때와 동일한 PID에서 실행됩니다. 이는 systemd가 해당 PID를 사용하여 데몬을 제어하므로(예: 서비스 중지 시 데몬 종료) 쉘 스크립트가 아닌 데몬이 되기를 원하기 때문에 중요합니다. 또한 아무런 이유 없이 공간만 차지하는 추가 셸 프로세스가 실행되는 것을 원하지 않습니다.
참고로 당신은 실제로할 수 있는~
쉘 스크립트 에서 사용하십시오 start_inplant.sh
. 이는 쉘 스크립트이기 때문에 쉘이 일반적으로 수행하는 모든 확장을 허용하고 수행합니다.
이 질문에 대한 다른 답변을 참고해 주세요.
이것은 실제로 작동하지 않습니다.
ExecStartPre=cd /home/inplant/IPSdevice/JAI1
systemd는 실제로 쉘 명령을 실행하지 않습니다(그리고 cd
내장 쉘입니다.) 이것은 /bin/cd
또는 /usr/bin/cd
바이너리가 있는 경우에만 작동하지만 그런 것은 없습니다(디렉토리 변경은 현재 프로세스에만 영향을 미치므로 외부 바이너리는 그렇지 않습니다) 그 자체에만 영향을 미치고 종료되므로 그 효과를 볼 수 없기 때문에 의미가 있습니다.)
셸을 사용하여 명시적으로 명령을 실행하는 경우에도 다음과 같습니다.
ExecStartPre=/bin/sh -c "cd /home/inplant/IPSdevice/JAI1"
이것은 현재 쉘에만 영향을 미치고 디렉토리 변경의 효과는 다른 명령, 특히 이 ExecStart=
명령에 전파되지 않기 때문에 작동하지 않습니다.
무슨 일인지 모르겠어요업무 문서ExecStartPre=
왜냐하면 명령이 실패하면 systemd는 실제로 단위 파일을 실행하지 않기 때문입니다 .할 수 있다systemd는 구문이 올바르지 않다고 생각하기 때문에(최신 버전까지 systemd 버전에서는 실행하는 명령에 대한 전체 경로가 필요함) 이 줄을 무시하고 기록하며 해당 줄을 건너뛰고 다음 줄로 이동합니다.
만약 그렇다면, 당신의 데몬은 실행 중이고 /home/inplant/IPSdevice/
그렇지 않은 것입니다. /home/inplant/IPSdevice/JAI1/
아마도 그곳에서는 잘 작동할 것입니다. 데몬(특히 잘 작성된 데몬)은 자신이 시작하는 디렉토리의 어떤 데몬에 관심이 없기 때문에 놀라지 않을 것입니다. 따라서 아마도 이 요구 사항이 있을 것입니다. 애초에 존재하지 않습니다.
또한 이 명령은 다음과 같습니다.
ExecStartPre=/bin/chown inplant.inplant /home/inplant/IPSdevice/JAI1
기본적으로 명령은 ExecStartPre=
지정된 자격 증명으로 실행되므로 해당 사용자로 이미 디렉터리를 생성했기 때문에 불필요해야 합니다(특히 이는 사용자에게 디렉터리를 생성할 수 있는 권한이 필요함을 의미함). 소유권 변경 . 이는 이미 생성된 디렉터리의 소유권이어야 하기 때문입니다.User=
Group=
mkdir
inplant
답변2
물결표는 셸별 확장이지만 단위 파일에 지정된 지침은 셸에서 실행되지 않습니다. ~
디렉터리의 절대 경로로 바꿔야 합니다 . Systemd는 이라는 작업 디렉터리를 찾고 있습니다 ~/IPSDevice/JAI1
.
답변3
ExecStartPre가 작업 디렉터리를 생성하더라도 존재하지 않는 디렉터리로 설정할 수 없다는 사실을 발견했습니다. 디렉터리를 생성한 후 해당 디렉터리로 변경하려면 ExecStartPre 지시문에서 cd를 사용해야 합니다. 작업 문서는 다음과 같습니다.
[Unit]
Description=JAI Device Service
# When systemd stops or restarts the app.service, the action is propagated to this unit
PartOf=app.service
# Start this unit after the app.service start
After=app-ips.service
[Service]
RuntimeDirectory=IPS-JAI1
User=inplant
Group=inplant
Environment=LD_LIBRARY_PATH=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib:/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam/bin/Linux64_x64:/opt/xview2_64/lib/:/opt/GO_SDK/lib/linux_x64
Environment=GENICAM_ROOT_V3_0=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam
ExecStartPre=/bin/mkdir -p /home/inplant/IPSdevice/JAI1
ExecStartPre=/bin/chown inplant.inplant /home/inplant/IPSdevice/JAI1
ExecStartPre=cd /home/inplant/IPSdevice/JAI1
ExecStartPre=/bin/ls -al /home/inplant/IPSdevice/JAI1
WorkingDirectory=/home/inplant/IPSdevice/
ExecStart=/home/inplant/IPSdevice/IPSdevice JAI1
# Restart the service on non-zero exit code when terminated by a signal other than SIGHUP, SIGINT, SIGTERM or SIGPIPE
Restart=on-failure
[Install]
# This unit should start when app.service is starting
WantedBy=app-ips.service
```