execute conky with a cron job and bash - bash

for my script in bash, I'd like to start conky if it's not running and pick a random wallpaper
#! /bin/bash
## dependances : randomize-lines
# otherwise wont work with cron
export DISPLAY=0
while read line ; do
echo $line | grep -vqe "^#"
if [ $? -eq 0 ]; then export $line; fi
done < ~/.dbus/session-bus/$(cat /var/lib/dbus/machine-id)-$DISPLAY
# random background
pathToImage="$HOME/Images/wallpaper/"
img="`find $pathToImage -name \*.jpg | rl | tail -n 1`"
/usr/bin/gconftool -t str -s /desktop/gnome/background/picture_filename $img
# test if conky is running
if ps ax | grep -v grep | grep conky > /dev/null
then
echo "conky running"
else
echo "conky is not running"
conky
fi
if I try to run the script within a terminal
$ ~/script/wallpaper/random-background.sh
conky is not running
Conky: can't open display: 0
if I put the test before the DISPLAY=0, it'll works in a terminal but not with cron
thank you

I think that should be
export DISPLAY=:0
but that won't work for
~/.dbus/session-bus/$(cat /var/lib/dbus/machine-id)-$DISPLAY
but you could change that to
~/.dbus/session-bus/$(cat /var/lib/dbus/machine-id)-0

You missed a ":":
export DISPLAY=:0

Related

How to evaluate results of pipes in a bash script

I need help for the following problem:
I'd like to kill all instances of a program, let's say xpdf.
At the prompt the following works as intended:
$ ps -e | grep xpdf | sed -n -e "s/^[^0-9]*\([0-9]*\)[^0-9]\{1,\}.*$/\1/p" | xargs kill -SIGTERM
(the sed-step is required to extract the PID).
However, there might be the case that no xpdf-process is running. Then it would be difficult, to embed the line into a script, because it aborts after it immediately with a message from kill. What can I do about it?
I tried (in a script)
#!/bin/bash
#
set -x
test=""
echo "test = < $test >"
test=`ps -e | grep xpdf | sed -n -e "s/^[^0-9]*\([0-9]*\)[^0-9]\{1,\}.*$/\1/p"`
echo "test = < $test >"
if [ -z "$test" ]; then echo "xpdf läuft nicht";
else echo "$test" | xargs -d" " kill -SIGTERM
fi
When running the script above I get
$ Kill_ps
+ test=
+ echo 'test = < >'
test = < >
++ ps -e
++ grep xpdf
++ sed -n -e 's/^[^0-9]*\([0-9]*\)[^0-9]\{1,\}.*$/\1/p'
+ test='21538
24654
24804
24805'
+ echo 'test = < 21538
24654
24804
24805 >'
test = < 21538
24654
24804
24805 >
+ '[' -z '21538
24654
24804
24805' ']'
+ xargs '-d ' kill -SIGTERM
+ echo '21538
24654
24804
24805'
kill: failed to parse argument: '21538
24654
24804
24805
Some unexpected happens: In test there are more PIDs then processes
At the prompt:
$ ps -e | grep xpd
21538 pts/3 00:00:00 xpdf.real
24654 pts/2 00:00:00 xpdf.real
When running the script again, the 24* PIDs change.
So here are my questions:
Where do the additional PIDs come from?
What can I do to handle the situation, in which no process I want to kill is running (or why does xargs not accept echo "$test" as input)? (I want my script not to be aborted)
Thanks in advance.
You can use pkill(1) or killall(1) instead of parsing ps output. (Parsing human-readable output for scripting is not recommended. This is an example.)
Usage:
pkill xpdf
killall xpdf # Note that on solaris, it kills all the processes that you can kill. https://unix.stackexchange.com/q/252349#comment435182_252356
pgrep xpdf # Lists pids
ps -C xpdf -o pid= # Lists pids
Note that tools like pkill, killall, pgrep will perform similar to ps -e | grep. So, if you do a pkill sh, it will try to kill sh, bash, ssh etc, since they all match the pattern.
But to answer your question about skipping xargs from running when there is nothing on the input, you can use -r option for (GNU) xargs.
-r, --no-run-if-empty
If the standard input does not contain any nonblanks, do not run the command.
Normally, the command is run once even if there is no input.
This option is a GNU extension.
This answer is for the case where killall or pkill (suggested in this answer) are not enough for you. For example if you really want to print "xpdf läuft nicht" if there is no pid to kill or applying kill -SIGTERM because you want to be sure of the signal you send to your pids or whatever.
You could use a bash loop instead of xargs and sed. It's pretty simple to iterate over CSV/column outputs:
count=0
while read -r uid pid ppid trash; do
kill -SIGTERM $pid
(( count++ ))
done < <(ps -ef|grep xpdf)
[[ $count -le 0 ]] && echo "xpdf läuft nicht"
There is a quicker way using pgrep (the previous one was for illustrate how to iterate over column-based outputs of commands with bash):
count=0
while read -r; do
kill -SIGTERM $REPLY
(( count++ ))
done < <(pgrep xpdf)
[[ $count -le 0 ]] && echo "xpdf läuft nicht"
If you're version of xargs can provide you the --no-run-if-empty you can still use it with pgrep (like suggested in this answer), but it's not available on the BSD or POSIX version. It is my case on macOS for example...
awk could also do the trick (with only one command after the pipe):
ps -ef|awk 'BEGIN {c="0"} {if($0 ~ "xpdf" && !($0 ~ "awk")){c++; system("kill -SIGTERM "$2)}} END {if(c <= 0){print "xpdf läuft nicht"}}'

Bash Script can run php script manually but cannot work in Cron

I have a bash script like this:
#!/bin/bash
log_file=/home/michael/bash/test.log
checkalive=checkalive.php
#declare
needRestart=0
#Check checkalive.php
is_checkalive=`ps aux | grep -v grep| grep -v "$0" | grep $checkalive| wc -l | awk '{print $1}'`
if [ $is_checkalive != "0" ] ;
then
checkaliveId=$(ps -ef | grep $checkalive | grep -v 'grep' | awk '{ printf $2 }')
echo "Service $checkalive is running. $checkaliveId"
else
echo "$checkalive OFF"
needRestart=1
fi
#NEED needRestart
if [ $needRestart == "1" ];
then
#START SERVICE
echo "Restarting services..."
/usr/bin/php5.6 /home/michael/bash/$checkalive >/dev/null 2>&1 &
echo "$checkalive..."
echo `date '+%Y-%m-%d %H:%M:%S'` " Start /home/michael/bash/$checkalive" >> $log_file
fi
I can run it manually but when I try to run it in Cron, it doesn't work for some reasons. Apparently the command:
/usr/bin/php5.6 /home/michael/bash/$checkalive >/dev/null 2>&1 &
does not work.
All of file permissions are already set to executable. Any advice?
Thank you
You have run into one of cron's most common mistakes, trying to use it like an arbitrary shell script. Cron is not a shell script and you can't do everything you can do in one, like dereferencing variables or setting arbitrary new variables.
I suggest you replace your values into the cron line and avoid usage of variables
/usr/bin/php5.6 /home/michael/bash/checkalive.php >/dev/null 2>&1 &
Also, consider removing the trailing & as it is not necessary.

Why is exit my status valid in command line but not within bash script? (Bash)

There are a few layers here, so bear with me.
My docker-container ssh -c"echo 'YAY!'; exit 25;" command executes echo 'YAY!'; exit 25; in my docker container. It returns:
YAY
error: message=YAY!
, code=25
I need to know if the command within the container was successful, so I append the following to the command:
docker-container ssh -c"echo 'YAY!'; exit 25;" >&1 2>/tmp/stderr; cat /tmp/stderr | grep 'code=' | cut -d'=' -f2 | { read exitStatus; echo $exitStatus; }
This sends the stderr to /tmp/stderr and, with the echo $exitStatus returns:
YAY!
25
So, this is exactly what I want. I want the $exitStatus saved to a variable. My problem is, I am placing this into a bash script (GIT pre-commit) and when this exact code is executed, the exit status is null.
Here is my bash script:
# .git/hooks/pre-commit
if [ -z ${DOCKER_MOUNT+x} ];
then
docker-container ssh -c"echo 'YAY!'; exit 25;" >&1 2>/tmp/stderr; cat /tmp/stderr | grep 'code=' | cut -d'=' -f2 | { read exitStatus; echo $exitStatus; }
exit $exitStatus;
else
echo "Container detected!"
fi;
That's because you're setting the variable in a pipeline. Each command in the pipeline is run in a subshell, and when the subshell exits the variable are no longer available.
bash allows you to run the pipeline's last command in the current shell, but you also have to turn off job control
An example
# default bash
$ echo foo | { read x; echo x=$x; } ; echo x=$x
x=foo
x=
# with "lastpipe" configuration
$ set +m; shopt -s lastpipe
$ echo foo | { read x; echo x=$x; } ; echo x=$x
x=foo
x=foo
Add set +m; shopt -s lastpipe to your script and you should be good.
And as Charles comments, there are more efficient ways to do it. Like this:
source <(docker-container ssh -c "echo 'YAY!'; exit 25;" 2>&1 1>/dev/null | awk -F= '/code=/ {print "exitStatus=" $2}')
echo $exitStatus

Bash Script issue, command not found, PATH seems to be correct

I have a issue with my Script, i am just trying to fingure out if my screen session is running or not (line 19).
The rest of the script is working.
#!/bin/bash
echo $PATH // /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
echo "0"
content=$(wget http://interwebs.com/index.php?page=count -q -O -)
z=$(($content / 5))
z=$(($z + 1))
echo $z // 4
lockfile=/var/tmp/mylock
if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then
trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
# do stuff here
x=1
count=0
while [ $x -le $z ]
do
$req ="$(ps -ef | grep -i mystatus$count | grep -v grep)"
if [ "$req" = "" ]; then
# run bash script
screen -amds mystatus$count /usr/bin/wget --spider interwebs.com/index.php?page=cronwhatsoever$(( $count +1))-$(( $count +5))
else
echo "Cron running"
fi
x=$(( $x + 1 ))
count=$(( $count +5))
done
# clean up after yourself, and release your trap
rm -f "$lockfile"
trap - INT TERM EXIT
else
echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi
sleep 15
It returns line 19: =: command not found. Actually running:
ps -ef | grep -i bukkit | grep -v grep
Works without issues if i run it directly in my Terminal, so any idea how to solve this issue?
I guess it something PATH related but grep is located in /bin/grep.
$req ="$(ps -ef | grep -i mystatus$count | grep -v grep)"
should be
req="$(ps -ef | grep -i mystatus$count | grep -v grep)"
Don't use $ on the left-hand side of an assignment, and you must not have spaces around the =

shell script not working through cron but manually

I'm using below command in a shell script:
echo "1" > log.txt
if [ `ifconfig eth0 | grep 'inet addr' | cut -d ":" -f 2 |
awk {'print $1'}` = 'ipaddress' ] && [ `whoami` = 'userid' ]; then
echo "2" >> log.txt
crontab -l > Cron.txt
echo "3" >> log.txt
fi
The script runs fine when run manually but when scheduled through cron, it
stucks at this IF.
cron entry: 31 11 * * * /home/abc/cron_backup.sh
Output in log.txt Manual run: prints 1,2,3 in log.txt through
cron: prints 1 in log.txt
I would suggest to put as first line of your script the command interpreter line #! to make sure that sh will run it
after that, have you consider to use double bracket syntax [[ ]]?
#!/bin/sh
echo "1" > log.txt
if [[ `ifconfig eth0 | grep 'inet addr' | cut -d ":" -f 2 |
awk {'print $1'}` = 'ipaddress' ]] && [[ `whoami` = 'userid' ]]; then
echo "2" >> log.txt
crontab -l > Cron.txt
echo "3" >> log.txt
fi
The problem could be with the ifconfig, grep, cut awk and whoami calls. When you run it from the command line you have your profile, which has your PATH setting.
When it is run from cron, it does not have your profile. If you modify your PATH variable to point to the location of these programs then you wouldn't have that change when run from cron.
Try putting in the full path for the each of the commands and see it that makes any difference when run from cron.

Resources