I have this service script:
[Unit]
Description=Description
[Service]
Type=simple
EnvironmentFile=/usr/local/etc/env.conf
ExecStart=/usr/local/bin/script.sh
User=my_user
Group=my_user
StandardOutput=journal
StandardError=journal
Restart=on-failure
RestartPreventExitStatus=13
RestartSec=10s
[Install]
WantedBy=multi-user.target
File script.sh looks as follow:
#!/usr/bin/env bash
echo "BOOM #1";
# /home/my_user/script.py
echo "BOOM #2";
File script.py looks as follow:
#!/usr/bin/env python
print "BOOM #P"
The problem is I do not see anything in journalctl if python script is commented. If I uncomment python script I will see in journalctl following lines:
BOOM #1
BOOM #P
I am suspecting that it might be some kind of buffering issue, but this is my guess. Any hint why to do to actually see echoes?
Related
This question may sound silly but I haven't been able to solve perhaps someone could help me.
I have a script called a.sh
# a.sh
source b.sh [ARGUMENT1] [ARGUMENT2]
echo "Running binding script"
echo $b_output
And here is what is on the b.sh script
# b.sh
b_output=$(virsh update-device "$1" "$2" --live --persistent)
export b_output
When you run virsh update-device... command in the terminal, the output of the command if succeded is the following:
>virsh update-device [ARGUMENT1] [ARGUMENT2] --live --persistent
Device updated successfully
However, When I run a.sh this is what I get:
Running binding script
Device
Is there a way I can export the entire output of the command run in the b.sh script, instead of only displaying the first word?
I just started to learn shells scripting.
Trying to run script in cron, without success. In telnet when i run "sh.script.sh" output is as expected. What I miss?
script.sh is in /usr/bin folder.
#!/bin/sh
var1 = $(opkg update)
echo ${var1}
try simply this:
#!/usr/bin/env bash
var1=$(opkg update)
echo $var1
Short Description:
I want to auto-start an executable (opencv binary file, generate via c++) via a systemd service-script after booting, but I am unsuccessful.
I narrowed down the error to the code statement "cv::imshow(....)" which opens a window and displays an image. At this point, the code throws the error: "QXcbConnection: Could not connect to display"
However, if I manually execute the sh-script or the binary, both work fine. I searched around stackoverflow for the most common errors, and I tried to fix all I could found. I am quite sure, that:
My service file actually runs at start (until the error occurred)
Manually execution of the binary file works fine
Manually execution of the .sh-script works fine
I do not have runtime-linking errors (see .sh-script)
I would appreciate any help. Please help me fix the error, and please explain to me, why this error even occurs in the first place. Thanks a lot :)
.
My system:
Machine: Raspberry Pi 3 Model B
Architecture: arm32 / ARMv7
OS: NOOBS
.
My script in /etc/systemd/system/ (test.service):
[Unit]
Description=lalala
[Service]
Type=oneshot
ExecStart=/bin/bash "/home/pi/Desktop/test.sh" start
ExecStop=/bin/bash "/home/pi/Desktop/test.sh" stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Moreover, I did execute the following commands:
sudo chmod u+rwx /etc/systemd/system/test.service
sudo systemctl enable test
And if I start the service manually, it runs with the same error output as while autostarting during the boot process:
sudo systemctl enable test
.
My shell script (test.sh):
#!/bin/sh -e
exec 2> /tmp/test.sh.log # send stderr to a log file
exec 1>&2 # send stdout to the same log file
set -x # tell sh to display commands before execution
echo "in script"
start()
{
echo "in start"
sleep 30
LD_LIBRARY_PATH=/usr/local/OpenCV/lib:/usr/local/SFML/lib:/usr/local/curl/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
/home/pi/Desktop/test/main -e &
}
# THE OTHER CASES, NOT PUT IN HERE (stop, status)
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
;;
*)
echo "Usage: {start|stop|status|restart}"
exit 1
;;
esac
exit 0
.
Minimal example of my source code: (executable)
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
int main()
{
cv::Mat frame;
cv::namedWindow("result", cv::WINDOW_NORMAL);
## CRASH
return 0;
}
.
P.S:
I am aware that there is a similar thread like this (Run OpenCV script on start with imshow). But as there is no solution for this question, and as I have more information to share, I thought it would be more appropriate to start a new thread.
Luckily, I solved the problem:
The problem was in the configuration of my serviced-script. I did know that I need a DISPLAY variable to the location of the X Display, but I was not aware of the fact that it needs authorization as well. This thread helped me figure it out:
https://unix.stackexchange.com/questions/85244/setting-display-in-systemd-service-file
In short:
Add these to lines to test.service in /etc/serviced/service:
Environment=XAUTHORITY=/home/pi/.Xauthority
Environment=DISPLAY=:0.0
[Unit]
Description=lalala
[Service]
Type=oneshot
ExecStart=/bin/bash "/home/pi/Desktop/test.sh" start
ExecStop=/bin/bash "/home/pi/Desktop/test.sh" stop
RemainAfterExit=yes
Environment=XAUTHORITY=/home/pi/.Xauthority
Environment=DISPLAY=:0.0
[Install]
WantedBy=multi-user.target
Full code
This article (https://news.ycombinator.com/item?id=9793466) makes a case for to sparsely use forking in systemd. Following this advice I try the following python service script:
import time
def run():
with open("/tmp/pysystemd/svc.out","w") as f:
while True:
print("***")
f.write("+++\n")
time.sleep(0.5)
run()
with the following systemd.service script:
[Unit]
Description=Simple zebra service
After=multi-user.target
[Service]
Type=Simple
#ExecStart = /usr/bin/python /tmp/pysystemd/svc.py > /tmp/pysystemd/std.out
ExecStart = /bin/bash -c '/usr/bin/python /tmp/pysystemd/svc.py > /tmp/pysystemd/std.out'
WorkingDirectory = /tmp/pysystemd
[Install]
WantedBy=multi-user.target
Though file /tmp/pysystemd/std.out is created it doesn't contain the expected output... Help appreciated.
Your output problem is probably buffered output. I don't see any output buffer flushes in your program.
See How to flush output of Python print?
Also, redirecting your output to your own log file isn't really the systemd way to do it. If you let your standard output and error go to defaults they will be in the journal and you can get it with journalctl -u my-service
I have this in /etc/init.d/unicorn
#!/bin/bash
# /etc/init.d/unicorn
# ### BEGIN INIT INFO
# chkconfig: 2345 95 016
# processname: unicorn
# dscription: Stop/start unicorn
### END INIT INFO
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
cmd() {
cd /vagrant
unicorn -p 3000 -D
}
# Start the service
start() {
su - vagrant -c cmd
}
### main logic ###
case "$1" in
start)
start
;;
*)
echo $"Usage: $0 {start}"
exit 1
esac
exit 0
I am trying to start unicorn in my local rails folder. I feel like this command should work:
su - vagrant -c cmd
and cannot figure out the reason.
I guess you are under the impression that the shell function cmd which is defined in that script should be available in the shell which has started that script earlier.
This is wrong, unless you sourced that script (which is unusual for scripts in /etc/init.d/). When you start a script (not source it), then you start a second process which executes the script. All definitions of shell functions (like that cmd) are valid only within that shell script and die with the process.
In case you really want the cmd to be available, you will have to source the script unicorn:
source /etc/init.d/unicorn
The su command, however, will still not be able to call that shell function because it only can call executables it can start using exec(), so they need to be a file. A shell function isn't.
To fix this, inline the function in the shell invoked by su:
start() {
su - vagrant -c 'cd /vagrant && unicorn -p 3000 -D'
}
and as for figuring out the reason in the first place, tooling is helpful:
$ shellcheck unicorn
In unicorn line 19:
su - vagrant -c cmd
^-- SC2033: Shell functions can't be passed to external commands.