Make Bash Script Recognize It Is Already Existent - bash

Question
How can I instruct my the bash script to not attempt to re-connect if to my rsync daemon if the process lock.file already exists? (as to prevent the bash script from attempting to infinitely create new connections after the first connection has already been made)?
This is an example of one of my rsync-daemon wrapper scripts:
#!/bin/sh
#
#
while [ 1 ]
do
cputool --load-limit 7.5 -- nice -n -15 rsync -avxP --no-i-r --rsync-path="rsync" --log-file=/var/log/rsync-home.log --exclude 'snap' --exclude 'lost+found' --exclude=".*" --exclude=".*/" 127.0.0.1::home /media/username/external/home-files-only && sync && echo 3 > /proc/sys/vm/drop_caches
if [ "$?" = "0" ] ; then
echo "rsync completed normally"
exit
else
echo "Rsync failure. Backing off and retrying..."
sleep 10
fi
done
#end of shell script
This is my /etc/rsyncd.conf:
[home]
path = /home/username
list = yes
use chroot = false
strict modes = false
uid = root
gid = root
read only = yes
# Data source information
max connections = 1
lock file = /var/run/rsyncd-home.lock
[prod-bkup]
path = /media/username/external/Server-Backups/Prod/today
list = yes
use chroot = false
strict modes = false
uid = root
gid = root
# Don't allow to modify the source files
read only = yes
max connections = 1
lock file = /var/run/rsyncd-prod-bkup.lock
[test-bkup]
path = /media/username/external/Server-Backups/Test/today
list = yes
use chroot = false
strict modes = false
uid = root
gid = root
# Don't allow to modify the source files
read only = yes
max connections = 1
lock file = /var/run/rsyncd-test-bkup.lock
[VminRoot2]
path = /root/VDI-Files
list = yes
use chroot = false
strict modes = false
uid = root
gid = root
# Don't allow to modify the source files
read only = yes
max connections = 1
lock file = /var/run/rsyncd-VminRoot2.lock

Thanks to #james-brown I now have multiple ways to ensure my script runs once.. correctly...
Solution 1 (quick & dirty):
flock -n <lock file> <script>
Or in my case, using this command to execute my cron job:
flock -n /var/run/rsyncd-home.lock /path/to/my_script.sh
caveat - this leaves your script vulnerable to stale lock files that may prevent execution on the next time interval.
Solution 2:
So, I used a bullet-proof method (so I think... I invite folks to correct my understanding, if need be)...
First, I did apt install procmail, then removed/hashed out the below two lines in my /etc/rsyncd.conf and ran systemctl restart rsync:
#max connections = 1
#lock file = /var/run/rsyncd-home.lock
From there I edited /usr/local/bin/backupscript.sh as follows:
#!/bin/bash
#
LOCK=/var/run/rsyncd-home.lock
remove_lock()
{
rm -f "$LOCK"
}
another_instance()
{
echo "There is another instance running, exiting"
exit 1
}
lockfile -r 0 -l 3600 "$LOCK" || another_instance
trap remove_lock EXIT
#new using rsyncd & perpetual restart
while [ 1 ]
do
cputool --load-limit 7.5 -- nice -n -15 rsync -avxP --no-i-r --rsync-path="rsync" --log-file=/var/log/rsync-home.log --exclude 'snap' --exclude="Variety Images" --exclude="Downloads/WebDev/Vmin-Vbox" --exclude 'Downloads/WebDev/Win10-Vbox' --exclude="Videos/other" --exclude 'lost+found' --exclude=".*" --exclude=".*/" 127.0.0.1::home /media/username/external/home-files-only && sync && echo 3 > /proc/sys/vm/drop_caches
if [ "$?" = "0" ] ; then
echo "rsync completed normally"
exit
else
echo "Rsync failure. Backing off and retrying..."
sleep 10
fi
done
#end of shell script
PRESTO:
The script will only connect to rsync daemon once, it will re-connect on dropped connections thanks to the while loop, and there is no danger of stale lock files interrupting my backup process at future intervals... (i.e. problem solved).
Very useful reference:
https://www.baeldung.com/linux/bash-ensure-instance-running

Related

“for” loop to get status of the service in bash script

I have a bash script where it will start the service and checks for the status of the service. But when I start the service the application will take 15 seconds to change the service status from "No" to "Yes" and my bash script returns status as "No" because it checks the status immediately after I start the service. So, I want a "for" loop for my bash script where it should checks for the status for every 1 second and breaks the for loop once it gets the status as "Yes" and should exit after 15 seconds.
app_start=`/usr/bin/AppStart.py`
app_status=`/usr/bin/AppStatus.py | grep -oPm1 "(?<=<Status>)[^<]+"`
if [[ $app_status = "Yes" ]] ; then
echo "Yes"
else
echo "No"
fi
The above command in my bash script will return the status immediately after I start the service.
Let me give you some pseudo-code for solving your issue:
boolean bFinish = false
integer iSeconds = 0
while (NOT(bFinish) AND (iSeconds < 15)) {
bFinish = check_if_app_status_is_Yes(...)
iSeconds = iSeconds + 1
sleep 1
}
For your information: sleep <x> is the correct UNIX/Linux command for pauzing the execution for <x> seconds.

Difference in behavior between shell and script

I have a set of commands that I am attempting to run in a script. To be exact, the lines are
rm tmp_pipe
mkfifo tmp_pipe
python listen_pipe.py &
while [ true ]; do nc -l -w30 7036 >>tmp_pipe; done &
listen_pipe.py is simply
if __name__ == "__main__":
f = open("tmp_pipe")
vals = " "
while "END" not in vals:
vals = f.readline()
if len(vals) > 0:
print(vals)
else:
f = open("tmp_pipe")
If I run the commands in the order shown I get my desired output, which is a connection to an ESP device that streams motion data. The connection resets after 30 seconds if the ESP device leaves the network range or if the device is turned off. The python script continues to read from the pipe and does not terminate when the tcp connection is reset. However, if I run this code inside a script file nc fails to connect and the device remains in an unconnected state indefinitely. The script is just
#!/bin/bash
rm tmp_pipe
mkfifo tmp_pipe
python listen_pipe.py &
while [ true ]; do nc -l -w30 7036 >>tmp_pipe; done &
This is being run on Ubuntu 16.04. Any suggestions are greatly welcomed, I have been fighting with this code all day. Thanks,
Ian

How to send message from zabbix to telegram?

I have problems with notifications on zabbix to telegram messenger.
So, I specified different guides for that. But not successful.
For example I use this guides
This solutions works for bash. But I can send this from zabbix.
export to=$1;
export subject=$2;
export body=$3;
tgpath=/usr/src/tg/zabbix
cd ${tgpath}
(sleep 5; echo "msg $to $subject $body"; echo "safe_quit") |
${tgpath}/telegram-cli -k /etc/telegram-cli/mykey.pub -W
Key telegram-cli -e does not work correctly with a login name and with format user#XXXXXX;
I dont want to use some API to send message.
Thank you for any help.
Your script is not equal to the blog post.
The steps are:
0 - Compile
cd /usr/src
git clone --recursive https://github.com/vysheng/tg.git
cd tg
./configure
make
mkdir viacron
cp bin/telegram-cli viacron/
cp tg-server.pub viacron/
cd viacron
1 - Create a file /usr/src/tg/viacron/telegram.config an put this:
default_profile = "viacron";
viacron = {
config_directory = "/usr/src/tg/viacron/";
};
2 - Create a file /usr/src/tg/viacron/telegram.config an put this:
#!/bin/bash
MAIN_DIRECTORY="/usr/src/tg/viacron/"
USER=$1
SUBJECT=$2
TEXT=$3
cd $MAIN_DIRECTORY
if [[ $? -ne 0 ]]; then
echo "Error to enter in the main directory"
exit 1
fi
./telegram-cli -k tg-server.pub -c telegram.config -WR -e "msg $USER $SUBJECT" || exit 1
exit 0
3 - Change permissions:
chmod +x /usr/src/tg/viacron/telegram_standalone.sh
chown -R yourUser: /usr/src/tg/
4 - Test:
/usr/src/tg/viacron/telegram_standalone.sh user#12345 "GNU is not unix"
5 - Put AlertScriptsPath=/usr/src/tg/viacron/ in zabbix_server.conf and restart the server
6 - In zabbix, add new media type with name telegram_standalone.sh
More information in https://gist.github.com/gnumoksha/a95f237d82733ce1f748 and http://tobias.ws/blog/zabbix-com-notificacoes-pelo-telegram/
Now Telegram supported by default
check:
https://www.zabbix.com/integrations/telegram
and there is extra settings check:
https://youtu.be/TpP6NpS9jjg?t=143

Lsyncd options issue

I am trying to use the software called lsyncd and it uses a configuration file written in lua to store the configuration options.
settings = {
logfile = "/logs/log.log",
pidfile = "/var/run/lsyncd.pid",
statusFile="/var/log/lsyncd.stat",
statusIntervall=5,
delay = 1
}
sync {
default.rsync,
source = "/source/folder",
target = "/destination/folder",
excludeFrom="/etc/exclude",
}
The manual talks about the ability to run commands on action there is even an example
fgroup = "staff"
-----
-- script for all changes.
--
command =
-- checks if the group is the one enforced and sets them if not
'[[
perm=`stat -c %A ^sourcePathname`
if test `stat -c %G ^sourcePathname` != ]]..fgroup..'[[; then
/bin/chgrp ]]..fgroup..'[[ ^sourcePathname || /bin/true;
fi
]] ..
-- checks if the group permissions are rw and sets them
'[[
if test `expr match $perm "....rw"` = 0; then
/bin/chmod g+rw ^sourcePathname || /bin/true;
fi
]] ..
-- and forces the executable bit for directories.
'[[
if test -d ^sourcePathname; then
if test `expr match $perm "......x"` -eq 0; then
/bin/chmod g+x ^^sourcePathname || /bin/true;
fi
fi
]]
-- on startup recursively sets all group ownerships
-- all group permissions are set to 'rw'
-- and to executable flag for directories
--
-- the hash in the first line is important, otherwise due to the starting
-- slash, Lsyncd would think it is a call to the binary /bin/chgrp only
-- and would optimize the shell call away.
--
startup =
'[[#
/bin/chgrp -R ]]..fgroup..'[[ ^source || /bin/true &&
/bin/chmod -R g+rw ^source || /bin/true &&
/usr/bin/find ^source -type d | xargs chmod g+x
]]
gforce = {
maxProcesses = 99,
delay = 1,
onStartup = startup,
onAttrib = command,
onCreate = command,
onModify = command,
-- does nothing on moves, they won't change permissions
onMove = true,
}
sync{gforce, source="/path/to/share"}
but I just want to execute a simple local command onCreate, onModify, onMove
/path/to/script.sh args
I know is probably simple but I can't figure it out.
Commands seem to be strings. Then I would try:
...
onStartup = "/path/to/script.sh args",
onAttrib = [[/path/to/script.sh args]], -- both '', "", and [[ ]] are string delimiters
....
Try something like this:
my_cmds =
[[
/path/to/script.sh args
]]
monitor =
{
delay = 1,
onAttrib = my_cmds,
onCreate = my_cmds,
onModify = my_cmds,
onMove = my_cmds,
}
sync
{
monitor,
source = "/source/folder",
target = "/destination/folder",
}
Please try the python script software Watcher, and configure the jobs.yml as the example.
......
events: ['create', 'modify', 'move']
......
command:/path/to/script.sh args

Catch PHP Exits in CLI via sh

Alright, I am trying to figure this problem out. I have a class that loops indefinitely until I either restart it manually or it runs out of available ram. I've written the code to be compliant with both CLI and normal web based execution. The only difference is with web-based execution the script will last about 12 hours or so until it crashes due to memory issues. When I run it in CLI it runs far longer, (On average 4-5 days before a crash due to memory)
The script is an IRC bot that is heavily customized for what I need it to do. I don't know enough of C++, ruby, python or other languages to make something that is cross platform compliant. My dev machine is Windows and my production server is Ubuntu. Right now I have the script successfully forking off and detaching from the terminal window so I can close that with out ending the script.
But what I am trying to figure out is how to catch errors and restart the script automatically since it tends to fail at random times and not always when I am at the IRC channel to catch the failure. One last positive would be a way to catch if I requested a restart from the channel and have the bot restart as I am constantly adding in new code functions or just general bug fixes.
Here is my CLI start php script
#!/usr/bin/php
<?php
include_once ("./config/base_conf.php");
include_once ("./libs/irc_base.php");
if ($config ['database'] == true) {
include_once ("./config/db_conf.php");
}
$server = getopt ( 's', array ("server::" ) );
if (! $server) {
$SER = 'default_server';
} elseif ($server ['server'] == 'raelgun') {
$SER = 'server_a';
} else {
$SER = 'default_server';
}
declare ( ticks = 1 )
;
$pid = pcntl_fork ();
if ($pid == - 1) {
die ( "could not fork" );
} else if ($pid) {
exit (); // we are the parent
} else {
// we are the child
}
// detatch from the controlling terminal
if (posix_setsid () == - 1) {
die ( "could not detach from terminal" );
}
$posid = posix_getpid ();
$PID_FILE = "/var/run/bot_process_".$SER.".pid";
$fp = fopen ($PID_FILE , "w" ) or die("File Exists Process Running");
fwrite ( $fp, $posid );
fclose ( $fp );
// setup signal handlers
pcntl_signal ( SIGTERM, "sig_handler" );
pcntl_signal ( SIGHUP, "sig_handler" );
// loop forever performing tasks
$bot = new IRC_BOT ( $config, $SER );
function sig_handler($signo) {
switch ($signo) {
case SIGTERM :
$bot->machineKill();
unlink($PID_FILE);
exit ();
break;
case SIGHUP :
$bot->machineKill();
unlink($PID_FILE);
break;
default :
// handle all other signals
}
}
Depending on the server I connect to since it connects to a maximum of 2 servers I run the following in the terminal to get the script running
php bot_start_shell.php --server="servernamehere" > /dev/null
So what I am trying to do is get a shell file coded correctly to monitor that script, and if it exits due to error or requested restart to restart the script.
I've used this technique for a while, where a shell script runs a PHP script, monitors the exit value and restarts.
Here's a test script that uses exit() to return a value to the shell script - 95,96 & 100 are taken as other 'unplanned restarts', handled at the bottom of the script.
#!/usr/bin/php
<?php
// cli-script.php
// for testing of the BASH script
exit (rand(95, 100));
/* normally we would return one of
# 97 - planned pause/restart
# 98 - planned restart
# 99 - planned stop, exit.
# anything else is an unplanned restart
*/
I prefer to wait a few seconds before I restart the script, to avoid wasting CPU if the script being called instantly fails, and so would be immediately restarted.
#!/bin/bash
# runPHP-Worker.sh
# a shell script that keeps looping until an exit code is given
# if its does an exit(0), restart after a second - or if it's a declared error
# if we've restarted in a planned fashion, we don't bother with any pause
# and for one particular code, we can exit the script entirely.
# The numbers 97, 98, 99 must match what is returned from the PHP script
nice php -q -f ./cli-script.php -- $#
ERR=$?
## Possibilities
# 97 - planned pause/restart
# 98 - planned restart
# 99 - planned stop, exit.
# 0 - unplanned restart (as returned by "exit;")
# - Anything else is also unplanned paused/restart
if [ $ERR -eq 97 ]
then
# a planned pause, then restart
echo "97: PLANNED_PAUSE - wait 1";
sleep 1;
exec $0 $#;
fi
if [ $ERR -eq 98 ]
then
# a planned restart - instantly
echo "98: PLANNED_RESTART, no pause";
exec $0 $#;
fi
if [ $ERR -eq 99 ]
then
# planned complete exit
echo "99: PLANNED_SHUTDOWN";
exit 0;
fi
# unplanned exit, pause, and then restart
echo "unplanned restart: err:" $ERR;
echo "sleeping for 1 sec"
sleep 1
exec $0 $#
If you don't want to do different things for each value, it really just comes down to
#!/bin/bash
php -q -f ./cli-script.php -- $#
exec $0 $#;

Resources