How to run inotifywait continuously and run it as a cron or deamon? - linux

I've built a shell script that uses inotifywait to automatically detect file changes on a specific directory. When a new PDF file is dropped in the directory this script should go off and it should then trigger ocropus-parser to execute some commands on it. The code:
#!/bin/sh
inotifywait -m ~/Desktop/PdfFolder -e create -e moved_to |
while read path action file; do
#echo "The file '$file' appeared in directory '$path' via '$action'"
# Check if the file is a PDF or another file type.
if [ $(head -c 4 "$file") = "%PDF" ]; then
echo "PDF found - filename: " + $file
python ocropus-parser.py $file
else
echo "NOT A PDF!"
fi
done
This works pretty well when I run this script through the terminal with ./filenotifier.sh but when I reboot my Linux (Ubuntu 14.04) my shell will no longer run and it will not restart after a reboot.
I've decided to create an init script that starts at boot time (I think). I did this by copying the file filenotifier.sh to init.d:
sudo cp ~/Desktop/PdfFolder/filenotifier.sh /etc/init.d/
I've then gave the file the correct rights:
sudo chmod 775 /etc/init.d/filenotifier.sh
and finally I've added the file to update-rc.d:
sudo update-rc.d filenotifier.sh defaults
However when I reboot and drop a PDF in the folder ~/Desktop/PdfFolder nothing will happen and it seems that the script does not go off.
I'm really not experienced with init.d, update-rc.d and deamon so I'm not sure what is wrong and if this is even a good approach or not.
Thanks,
Yenthe

Being an init-script, you should add the LSB header to your script, like this:
#!/bin/sh
### BEGIN INIT INFO
# Provides: filenotifier
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Something
# Description: Something else
### END INIT INFO
inotifywait -m ...
This way, you can ensure that your script runs when all mount points are available (thanks to Required-Start: $remote_fs). This is essential if your home directory is not on the root partition.
Another problem is that in your init-script you're using ~:
inotifywait -m ~/Desktop/PdfFolder ...
The ~ expands to the current user home directory. Init-scripts are run as root, so it'll expand to /root/Desktop/PdfFolder. Use ~<username> instead:
inotifywait -m ~yenthe/Desktop/PdfFolder ...
(Assuming that your username is yenthe.)
Or perhaps switch user before starting (using sudo).
$file is the basename without the path to the directory. Use "$path/$file" in your commands:
"$(head -c 4 "$path/$file")"
python ocropus-parser.py "$path/$file"
Maybe consider using name instead of file, to avoid confusion.
If things are not working, or if in general you want to investigate something, remember to use ps, like this:
ps -ef | grep inotifywait
ps will tell you, for example, whether your script is running and if inotifywait was launched with the correct arguments.
Last but not least: use "$file", not $file; use "$(head -c 4 "$file")", not $(head -c 4 "$file"); use read -r, not read. These tips can save you a lot of headaches in the future!

For that purpose the developers of inotify created incron. It is a cron like daemon which executes scripts based on changes in a watched file/directory rather than on time events.

Related

Is it possible to auto reboot for 5 loops through mint?

I am currently using the following command to run reboot
sudo shutdown -r now
however, I would need to run it for 5 loops before and after executing some other programs. Was wondering if it is possible to do it in MINT environment?
First a disclaimer: I haven't tried this because I don't want to reboot my machine right now...
Anyway, the idea is to make a script that can track it's iteration progress to a file as #david-c-rankin suggested. This bash script could look like this (I did test this):
#!/bin/sh
ITERATIONS="5"
TRACKING_FILE="/path/to/bootloop.txt"
touch "$TRACKING_FILE"
N=$(cat "$TRACKING_FILE" | wc -c)
if [ "$N" -lt "$ITERATIONS" ]; then
printf "." >> "$TRACKING_FILE"
echo "rebooting (iteration $N)"
# TODO: this is where you put the reboot command
# and anything you want to run before rebooting each time
else
rm "$TRACKING_FILE"
# TODO: other commands to resume anything required
fi
Then add a call to this script somewhere where it will be run on boot. eg. cron (#reboot) or systemd. Don't forget to remove it from a startup/boot command when you're finished or next time you reboot, it will reboot N times.
Not sure exactly how you are planning on using it, but the general workflow would look like:
save script to /path/to/reboot_five_times.sh
add script to run on boot (cron, etc.)
do stuff (manually or in a script)
call the script
computer reboots 5 times
anything in the second TODO section of the script is then run
go back to step 3, or if finished remove from cron/systemd so it won't reboot when you don't want it to.
First create a text document wherever you want,I created one on Desktop,
Then use this file as a physical counter and write a daemon file to run things at startup
For example:
#!/bin/sh
var=$(cat a.txt)
echo "$var"
if [ "$var" != 5 ]
then
var=$((var+1))
echo "$var" > a.txt
echo "restart here"
sudo shutdown -r now
else
echo "stop restart"
echo 0 > a.txt
fi
Hope this helps
I found a way to create a file at startup for my reboot script. I incorporated it with the answers provided by swalladge and also shubh. Thank you so much!
#!/bin/bash
#testing making a startup application
echo "
[Desktop Entry]
Type=Application
Exec=notify-send success
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name[en_CA]=This is a Test
Name=This is a Test
Comment[en_CA]=
Comment=" > ~/.config/autostart/test.desktop
I create a /etc/rc.local file to execute user3089519's script, and this works for my case. (And for bootloop.txt, I put it here: /usr/local/share/bootloop.txt )
First: sudo nano /etc/rc.local
Then edit this:
#!/bin/bash
#TODO: things you want to execute when system boot.
/path/to/reboot_five_times.sh
exit 0
Then it works.
Don't forget edit /etc/rc.local and remove /path/to/reboot_five_times.sh when you done reboot cycling.

inotifywait shell script run as daemon

I have a script that watches a directory (recursively) and performs a command when a file changes. This is working correctly when the monitoring flag is used as below:
#!/bin/sh
inotifywait -m -r /path/to/directory |
while read path action file; do
if [ <perform a check> ]
then
my_command
fi
done
However, I want to run this on startup and in the background, so naïvely thought I could change the -m flag to -d (run inotifywait as daemon, and include an --outfile location) and then add this to rc.local to have this run at startup. Where am I going wrong?
Well .... with -d it backgrounds itself and outputs ONLY to outfile, so your whole pipe & loop construct is moot, and it never sees any data.
Incron is a cron-like daemon for inotify events.
Just need to use incrontab and an entry for your task:
/path/to/directory IN_ALL_EVENTS /usr/local/bin/my-script $# $# $%
And /local/bin/my-script would be:
#! /bin/bash
local path=$1
local action=$2
local file=$3
if [ <perform a check> ]
then
my_command
fi
You need to add a single & to the end of command in your /etc/rc.local
Putting a single & at the end of a command means Run this program in the background so the user can still have input.

Run Linux Shell Script On Boot

I have a Shell script that I want to run on boot. Every time that I start the device It'll run the script in the background.
The script contains a while true loop and suppose to run constantly, at least until the device will be turned off. This is the script :
#!/bin/bash
cd /home/.../
while true
do
sh ./update_logs.sh
sleep 1
done
After of plenty of searches I've came up with too much information which made a salad in my head. I've been advised to get to this folder /etc/init.d and put down my script there by using special pattern (LSB-compliant) which looks like this :
!#/bin/sh
start () {
echo "application started";
./helloworld # you should use an absolute path here instead of ./
}
stop () {
}
case "$1" in
start)
start
;;
stop)
stop
;;
*)
echo "Usage start|stop";
esac
exit $?
Make the script executable by chmod +x, then make A symbolic link for the file by typing ln -s /etc/rc.d/init.d/run_update.sh /etc/init.d/rc5.d/S90run_update
This supposed to be the "hard way" while the "easy way" is putting my script in a folder /etc/rc.local where it shall boot my script after the main boot process.
Well, I don't have this kind of folder. What I to have in etc folder is rc.d which leads to sub folders : init.d rc0.d rc1.d rc2.d... rc6.d
If the solution is the hard way by writing the code above, what is the minimum that I need to include in it? since I see different type of codes which include ### with descriptions and run levels
I have a Linux Red Hat 4.6.3-2.
in DEBIAN script should have at top
#!/bin/sh
### BEGIN INIT INFO
# Provides: SCRIPT_NAME_HERE_NO_PATH
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start daemon at boot time
# Description: Enable service provided by daemon.
### END INIT INFO
....
then in shell must enable rc system links
update-rc.d SCRIPT_NAME_HERE_NO_PATH defaults
update-rc.d SCRIPT_NAME_HERE_NO_PATH enable
OK I think I understand.
start a konsole session, then look for a hidden file called .bash_profile. If you do not find it in your home directory then it does not exit. Create it with pico (use pico .bash_profile).
If the file exist, edit it with a link to your script.
The next time you log into your system that file will run.
HOpe this helps.
1. Add below lines in intit.rc:
chmod 0755 /system/bin/shellscript_name //giving permissions to your shell_script
start name_your_service //starting your shellscrip
service name_your_service /system/bin/shellscript_name
class main
user root
group shell system
seclabel u:r:shell:s0
disabled
2. Goto the vendor directory and create your shell script under system/bin/shellscript_name.
3. Add your shell script under Android MakeFile:
include $(CLEAR_VARS)
LOCAL_MODULE := module_name
LOCAL_MODULE_OWNER := owner_name
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := path to your .sh
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/bin/
include $(BUILD_PREBUILT)

user-data (cloud-init) script not executing on EC2

my user-data script
#!
set -e -x
echo `whoami`
su root
yum update -y
touch ~/PLEASE_WORK.txt
which is fed in from the command:
ec2-run-instances ami-05355a6c -n 1 -g mongo-group -k mykey -f myscript.sh -t t1.micro -z us-east-1a
but when I check the file /var/log/cloud-init.log, the tail -n 5 is:
[CLOUDINIT] 2013-07-22 16:02:29,566 - cloud-init-cfg[INFO]: cloud-init-cfg ['runcmd']
[CLOUDINIT] 2013-07-22 16:02:29,583 - __init__.py[DEBUG]: restored from cache type DataSourceEc2
[CLOUDINIT] 2013-07-22 16:02:29,686 - cloud-init-cfg[DEBUG]: handling runcmd with freq=None and args=[]
[CLOUDINIT] 2013-07-22 16:02:33,691 - cloud-init-run-module[INFO]: cloud-init-run-module ['once-per-instance', 'user-scripts', 'execute', 'run-parts', '/var/lib/cloud/data/scripts']
[CLOUDINIT] 2013-07-22 16:02:33,699 - __init__.py[DEBUG]: restored from cache type DataSourceEc2
I've also verified that curl http://169.254.169.254/latest/user-data returns my file as intended.
and no other errors or the output of my script happens. how do I get the user-data scrip to execute on boot up correctly?
Actually, cloud-init allows a single shell script as an input (though you may want to use a MIME archive for more complex setups).
The problem with the OP's script is that the first line is incorrect. You should use something like this:
#!/bin/sh
The reason for this is that, while cloud-init uses #! to recognize a user script, the operating system needs a complete shebang line in order to execute the script.
So what's happening in the OP's case is that cloud-init behaves correctly (i.e. it downloads and tries to run the script) but the operating system is unable to actually execute it.
See: Shebang (Unix) on Wikipedia
Cloud-init does not accept plain bash scripts, just like that. It's a beast that eats YAML file that defines your instance (packages, ssh keys and other stuff).
Using MIME you can also send arbitrary shell scripts, but you have to MIME-encode them.
$ cat my-boothook.txt
#!/bin/sh
echo "Hello World!"
echo "This will run as soon as possible in the boot sequence"
$ cat my-user-script.txt
#!/usr/bin/perl
print "This is a user script (rc.local)\n"
$ cat my-include.txt
# these urls will be read pulled in if they were part of user-data
# comments are allowed. The format is one url per line
http://www.ubuntu.com/robots.txt
http://www.w3schools.com/html/lastpage.htm
$ cat my-upstart-job.txt
description "a test upstart job"
start on stopped rc RUNLEVEL=[2345]
console output
task
script
echo "====BEGIN======="
echo "HELLO From an Upstart Job"
echo "=====END========"
end script
$ cat my-cloudconfig.txt
#cloud-config
ssh_import_id: [smoser]
apt_sources:
- source: "ppa:smoser/ppa"
$ ls
my-boothook.txt my-include.txt my-user-script.txt
my-cloudconfig.txt my-upstart-job.txt
$ write-mime-multipart --output=combined-userdata.txt \
my-boothook.txt:text/cloud-boothook \
my-include.txt:text/x-include-url \
my-upstart-job.txt:text/upstart-job \
my-user-script.txt:text/x-shellscript \
my-cloudconfig.txt
$ ls -l combined-userdata.txt
-rw-r--r-- 1 smoser smoser 1782 2010-07-01 16:08 combined-userdata.txt
The combined-userdata.txt is the file you want to paste there.
More info here:
https://help.ubuntu.com/community/CloudInit
Also note, this highly depends on the image you are using. But you say it is really cloud-init based image, so this applies. There are other cloud initiators which are not named cloud-init - then it could be different.
This is a couple years old now, but for others benefit I had the same issue, and it turned out that cloud-init was running twice, from inside /etc/rc3.d . Deleting these files inside the folder allowed the userdata to run correctly:
lrwxrwxrwx 1 root root 22 Jun 5 02:49 S-1cloud-config -> ../init.d/cloud-config
lrwxrwxrwx 1 root root 20 Jun 5 02:49 S-1cloud-init -> ../init.d/cloud-init
lrwxrwxrwx 1 root root 26 Jun 5 02:49 S-1cloud-init-local -> ../init.d/cloud-init-local
The problem is with cloud-init not allowing the user script to run on the next start-up.
First remove the cloud-init artifacts by executing:
rm /var/lib/cloud/instances/*/sem/config_scripts_user
And then your userdata must look like this:
#!/bin/bash
echo "hello!"
And then start you instance. It now works (tested).

dpkg remove to stop processes

I am currently running Ubuntu 12.04. I've created a debian package that currently installs successfully and starts three new processes. I have also made these three processes start at runtime by placing the following script inside /etc/init.d:
# This example is from http://www.debian-administration.org/article/Making_scripts_run_at_boot_time_with_Debian
# Also used http://wiki.debian.org/LSBInitScripts/
### BEGIN INIT INFO
# Provides: bleh
# Required-Start: $remote_fs $syslog $network
# Required-Stop: $remote_fs $syslog $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start daemon at boot time
# Description: Enable service provided by daemon.
### END INIT INFO
# Carry out specific functions when asked to by the system
case "$1" in
start)
cd //opt/bleh
attrf=.gatewayattributes
if [ ! -z "$1" ]
then
echo "[gateway]" >> $attrf
echo "activationKey = $1" >> $attrf
fi
./bleh1 -n &
./bleh2 &
python bleh3 &
;;
stop)
cd //opt/bleh
/usr/bin/pkill -f ./bleh1 -n
/usr/bin/pkill -f bleh3
kill -9 $(pidof bleh2)
rm -rf logs
;;
This script does start the three processes at runtime, but for some reason I cannot actually use the start/stop commands, as in sudo /etc/init.d bleh.sh stop.
An even bigger issue is that removing this package using the command:
sudo dpkg -r bleh
Does not actually stop the three processes, it only tries to remove the bleh directory I installed in my opt folder. Also, I have a folder inside my bleh directory which does not get removed, it gives me a warning stating:
Removing bleh ...
dpkg: warning: while removing bleh, directory '/opt/bleh/logs' not empty so not removed.
The files inside of that logs directory are read-only unless you have SU priviledges, but I don't see how that should be a problem as I am calling sudo on that dpkg -r command.
If I run sudo dpkg -r bleh again, it states there's no installed package matching bleh, meaning it thinks it has successfully removed the installed package, even with that exisiting logs directory and the three processes which are still running.
Sorry, I know this was long, but I could really use some help.. thanks in advance!
As recommended by the Debian New Maintainer's Guide, please use dh_installinit (building your whole package with debhelper, of course). By default, this will add scripts to start and stop on package installation and removal.
Auxiliary files (such as configuration) are usually removed in purge (e.g. dpkg -P) state. To handle this yourself, you need a deconfigure script.
Also, it is highly preferable to use start-stop-daemon instead of &, which is insufficient for proper daemonization.

Resources