assign output of command to variable in bash script run by root cron - linux

I have been trying to write a script that will backup my minecraft server but only run if I am not actively on the server. The way i am trying to do this is by parsing the output of top and grepping the process name and getting the CPU usage. When I am not on the server the usage is usually less than 10. The server is run as a service so in order to bring it down before the backup and to bring it back up I need to use systemctl stop and systemctl start in so it need to be run as root. This is the script I have:
#!/bin/bash
PATH="$PATH:/usr/bin:/bin"
CPU=`/usr/bin/top -b n1 | /usr/bin/grep bedrock_server | /usr/bin/awk '{ print $9 }' | /usr/bin/cut -d . -f 1`
DATE=`date '+\%m-\%d'`
dirname="/home/brandon/bedrock-backups/$DATE"
if [ "$CPU" -lt 20 ];
then
systemctl stop bedrock-server.service && \
mkdir -p $dirname && chown brandon $dirname && chmod 777 $dirname && \
cd /home/brandon && \
tar -czf $dirname/bedrock-backup.tar bedrock/ && \
chown brandon $dirname/bedrock-backup.tar && chmod 777 $dirname/bedrock-backup.tar && \
echo "Backup Completed Successfully" && \
systemctl start bedrock-server.service
else
echo "Backup terminated due to server activity" && \
exit
fi
The issue seems to be that the output of the top command and all the subsequent parsing does not get assigned to CPU so the script errors out at if [ "$CPU" -lt 20 ] with the error integer expression expected. I tried to run the script in cron's env by adding the line env > ~/cronenv to root's crontab and have it run once then use env - `cat ~/cronenv` /bin/sh to get into crons environment. I run
CPU=`top -b n1 | grep bedrock_server | awk '{ print $9 }' | cut -d . -f 1`
and it works. I tried again as a cron job and I get the same error. Then I read that full paths to commands should be used inside cron so I added /usr/bin to the commands as seen above.
I've tried using #!/bin/sh as well as #!/bin/bash for the shebang. The crontab entry is as follows :
# m h dom mon dow command
SHELL=/bin/bash
PATH="$PATH:/usr/bin:/bin"
27 22 * * * /bin/bash /home/brandon/bin/scripts/backup-bedrock
#* * * * * env > ~/cronenv
I can even run the full script in the cronenv but not scheduled as a cron job.
I do not know what else to try or what I am doing wrong, hoping someone can help me.
Thanks!
Also this is on Ubuntu 20.04 if that matters

Related

How to run script multiple times and after every execution of command to wait until the device is ready to execute again?

I have this bash script:
#!/bin/bash
rm /etc/stress.txt
cat /dev/smd10 | tee /etc/stress.txt &
for ((i=0; i< 1000; i++))
do
echo -e "\nRun number: $i\n"
#wait untill module restart and bee ready for next restart
dmesg | grep ERROR
echo -e 'AT+CFUN=1,1\r\n' > /dev/smd10
echo -e "\nADB device booted successfully\n"
done
I want to restart module 1000 times using this script.
Module is like android device witch has linux inside it. But I use Windows.
AT+CFUN=1,1 - reset
When I push script, after every restart I need a command which will wait module and start up again and execute script 1000 times. Then I do pull in .txt file and save all output content.
Which command should I use?
I try commands like wait, sleep, watch, adb wait-for-device, ps aux | grep... Nothing works.
Can someone help me with this?
I find the solution. This is how my script actually looks:
#!/bin/bash
cat /dev/smd10 &
TEST=$(cat /etc/output.txt)
RESTART_TIMES=1000
if [[ $TEST != $RESTART_TIMES ]]
then
echo $((TEST+1)) > /etc/output.txt
dmesg
echo -e 'AT+CFUN=1,1\r\n' > /dev/smd10
fi
These are the steps that you need to do:
adb push /path/to/your/script /etc/init.d
cd /etc
cat outputfile.txt - make an output file and write inside file 0 ( echo 0 > output.txt )
cd init.d
ls - you should see rc5.d
cd .. then cd rc5.d - go inside
ln -s ../init.d/yourscript.sh S99yourscript.sh
ls - you should see S99yourscript.sh
cd .. return to init.d directory
chmod +x yourscript.sh - add permision to your script
./yourscript.sh

How to check if user has sudo privileges inside the bash script?

I would like to check if the user has sudo privileges. This is an approximate example of what I am trying to do. I am trying to get this to work across the following os: centos, ubuntu, arch.
if userIsSudo; then
chsh -s $(which zsh)
fi
Try with this:
$ sudo -v &> /dev/null && echo "Sudoer" || echo "Not sudoer"
Also, IDK how secure will be searching for his membership in the sudo group, i.e:
$ groups "$(id -un)" \
| grep -q ' sudo ' \
&& echo In sudo group \
|| echo Not in sudo group
Or:
$ getent group sudo \
| grep -qE "(:|,)$(id -un)(,|$)" \
&& echo in sudo group \
|| echo not in sudo group
sudo -l will display the commands that the user can run with sudo privileges. If there are no commands that can be run, sudo -l will return an error code and so you could try:
sudo -l && chsh -s $(which zsh)
Usually when you run an script you want to know if end it well or you got an error or what kind of error you got if there was any.
This is a more elaborated snippet, sudoer-script.sh:
## Define error code
E_NOTROOT=87 # Non-root exit error.
## check if is sudoer
if ! $(sudo -l &> /dev/null); then
echo 'Error: root privileges are needed to run this script'
exit $E_NOTROOT
fi
## do something else you
## means it was successfully executed
exit 0
Now you can reuse your script, pipe it or concatenate with other commands
sudoer-script.sh && ls
## in a script
if $(sudoer-script.sh); then
echo 'success'
fi
## capture error
stderr=$(./sudoer-script.sh 2>&1 >/dev/null)
echo $stderr
As a function:
is_sudoer() {
## Define error code
E_NOTROOT=87 # Non-root exit error.
## check if is sudoer
if ! $(sudo -l &> /dev/null); then
echo 'Error: root privileges are needed to run this script'
return $E_NOTROOT
fi
return 0
}
if is_sudoer; then
echo "Sudoer"
else
echo "Not sudoer"
fi

What causes multiple Mails when using Cron with Bash Script

I've made a little bash script to backup my nextcloud files including my database from my ubuntu 18.04 server. I want the backup to be executed every day. When the job is done I want to reseive one mail if the job was done (additional if it was sucessful or not). With the current script I reseive almost 20 mails and I can't figure out why. Any ideas?
My cronjob looks like this:
* 17 * * * "/root/backup/"backup.sh >/dev/null 2>&1
My bash script
#!/usr/bin/env bash
LOG="/user/backup/backup.log"
exec > >(tee -i ${LOG})
exec 2>&1
cd /var/www/nextcloud
sudo -u www-data php occ maintenance:mode --on
mysqldump --single-transaction -h localhost -u db_user --password='PASSWORD' nextcloud_db > /BACKUP/DB/NextcloudDB_`date +"%Y%m%d"`.sql
cd /BACKUP/DB
ls -t | tail -n +4 | xargs -r rm --
rsync -avx --delete /var/www/nextcloud/ /BACKUP/nextcloud_install/
rsync -avx --delete --exclude 'backup' /var/nextcloud_data/ /BACKUP/nextcloud_data/
cd /var/www/nextcloud
sudo -u www-data php occ maintenance:mode --off
echo "###### Finished backup on $(date) ######"
mail -s "BACKUP" name#domain.com < ${LOG}
Are you sure about the CRON string? For me this means "At every minute past hour 17".
Should be more like 0 17 * * *, right?

Shell script to run two scripts when server load is above 20

I need a script that I can run on a cron every 5 minutes that will check if server load is above 20 and if it is it will run two scripts.
#!/bin/bash
EXECUTE_ON_AVERAGE="15" # if cpu load average for last 60 secs is
# greater or equal to this value, execute script
# change it to whatever you want :-)
while true; do
if [ $(echo "$(uptime | cut -d " " -f 13 | cut -d "," -f 1) >= $EXECUTE_ON_AVERAGE" | bc) = 1 ]; then
sudo s-
./opt/tomcat-latest/shutdown.sh
./opt/tomcat-latest/startup.sh
else
echo "do nothing"
fi
sleep 60
done
I then chmod +x the file.
When I run it I get this:
./script.sh: line 10: ./opt/tomcat-latest/shutdown.sh: No such file or directory
./script.sh: line 11: ./opt/tomcat-latest/startup.sh: No such file or directory
From the looks of it, your script is trying to execute the two scripts from the current working directory into opt/tomcat-latest/ -- which doesn't exist. You should confirm the full file paths for the two shell scripts and then use that instead of the current path.
Also, I'd recommend that you create a cron to do this task. Here's some documentation about the crontab. https://www.gnu.org/software/mcron/manual/html_node/Crontab-file.html
check the permission to execute the files shutdown.sh and startup.sh
Is sudo -s not sudo s-
And I recommend to put a sleep (seconds)
sudo -s /opt/tomcat-latest/shutdown.sh
sleep 15
sudo -s /opt/tomcat-latest/startup.sh
Or better
sudo -s /opt/tomcat-latest/shutdown.sh && sudo -s /opt/tomcat-latest/startup.sh
The startup.sh will executed only if shutdown.sh was executed with success.

TERM environment variable not set

I have a file.sh with this, when run show : TERM environment variable not set.
smbmount //172.16.44.9/APPS/Interfas/HERRAM/sc5 /mnt/siscont5 -o
iocharset=utf8,username=backup,password=backup2011,r
if [ -f /mnt/siscont5/HER.TXT ]; then
echo "No puedo actualizar ahora"
umount /mnt/siscont5
else
if [ ! -f /home/emni/siscont5/S5.TXT ]; then
echo "Puedo actualizar... "
touch /home/emni/siscont5/HER.TXT
touch /mnt/siscont5/SC5.TXT
mv -f /home/emni/siscont5/CCORPOSD.DBF /mnt/siscont5
mv -f /home/emni/siscont5/CCTRASD.DBF /mnt/siscont5
rm /mnt/siscont5/SC5.TXT
rm /home/emni/siscont5/HER.TXT
echo "La actualizacion ha sido realizada..."
else
echo "No puedo actualizar ahora: Interfaz exportando..."
fi
fi
umount /mnt/siscont5
echo "/mnt/siscont5 desmontada..."
You can see if it's really not set. Run the command set | grep TERM.
If not, you can set it like that:
export TERM=xterm
Using a terminal command i.e. "clear", in a script called from cron (no terminal) will trigger this error message. In your particular script, the smbmount command expects a terminal in which case the work-arounds above are appropriate.
You've answered the question with this statement:
Cron calls this .sh every 2 minutes
Cron does not run in a terminal, so why would you expect one to be set?
The most common reason for getting this error message is because the script attempts to source the user's .profile which does not check that it's running in a terminal before doing something tty related. Workarounds include using a shebang line like:
#!/bin/bash -p
Which causes the sourcing of system-level profile scripts which (one hopes) does not attempt to do anything too silly and will have guards around code that depends on being run from a terminal.
If this is the entirety of the script, then the TERM error is coming from something other than the plain content of the script.
You can replace :
export TERM=xterm
with :
export TERM=linux
It works even in kernel with virgin system.
SOLVED: On Debian 10 by adding "EXPORT TERM=xterm" on the Script executed by CRONTAB (root) but executed as www-data.
$ crontab -e
*/15 * * * * /bin/su - www-data -s /bin/bash -c '/usr/local/bin/todos.sh'
FILE=/usr/local/bin/todos.sh
#!/bin/bash -p
export TERM=xterm && cd /var/www/dokuwiki/data/pages && clear && grep -r -h '|(TO-DO)' > /var/www/todos.txt && chmod 664 /var/www/todos.txt && chown www-data:www-data /var/www/todos.txt
If you are using the Docker PowerShell image set the environment variable for the terminal like this with the -e flag
docker run -i -e "TERM=xterm" mcr.microsoft.com/powershell

Resources