Passing commands to named screen session via .sh script - bash

I'm completely beginner with this, I googled some if elseif else tutorial and started to build this script. I'm trying to create a .sh script which gives me option to manage my valves sourceserver from the PHP script. This is what I have currently:
#!/bin/sh
# CONFIG
LOGFILE="/var/www/management/ifacelog"
NEWDATE=`TZ=GMT-3 date +%d.%m.%Y" "%H:%M:%S`
# END OF CONFIG
SCRIPTCOMMAND=$1
CSGOCOMMAND=$2
if [ $SCRIPTCOMMAND = "START" ] ; then
echo $NEWDATE "SERVER STARTED! connect cs.kask.fi; password gd | rcon_password tuksu" >> test
touch lockfile
screen -A -m -d -S csgo -L /home/csgo/server/srcds_run -game csgo -console -usercon -tickrate 128 +net_public_adr 46.246.93.192 +ip 46.246.93.192 +tv_port 27010 -maxplayers_override 11 +game_type 0 +game_mode 1 +host_worksh$
elif [ $SCRIPTCOMMAND = "RESTART" ] ; then
echo $NEWDATE "STOPPING THE SERVER" >> test
echo $NEWDATE "Passing command tv_stoprecord and waiting 10sec." >> test
screen -S csgo -X stuff "tv_stoprecord"
screen -S csgo -X stuff "
"
sleep 10
echo $NEWDATE "Passing command: quit" >> test
screen -S csgo -X stuff "quit"
screen -S csgo -X stuff "
"
echo $NEWDATE "SERVER RESTARTED!" >> test
elif [ $SCRIPTCOMMAND = "KILL" ]; then
echo $NEWDATE "KILLING SERVER!" >> test
pkill srcds_run
rm lockfile
rm screenlog.0
elif [ $SCRIPTCOMMAND = "RCON" ]; then
echo $NEWDATE "REMOTE RCON! Passing value: " $2 $3 >> test
screen -X -S csgo -p 0 stuff $2 $3
screen -S csgo -X stuff "
"
elif [ $SCRIPTCOMMAND = "RESET" ]; then
rm lockfile
rm screenlog.0
else
echo "UNKNOWN COMMAND WAS PASSED!"
fi
Everything is working except passing commands to screen session itself (If scriptcommand = RCON). If I type in shell screen -X -S csgo -p 0 stuff say test, it passes it to screen session properly. If I run my script ./csgo.sh RCON say test, screen says error -X: stuff: invalid option "say". I tried also with screen -X -S csgo -p 0 stuff \"$2\" but that didn't make any difference.
Since this works fine if I type it manually, I have no idea why it doesn't work on script. Any idea why it doesn't work and how to fix it?

Related

Delete first line/chars on Windows Pipe

I'm trying to capture a live tcpdump from a custom designed linux system. The command I'm using so far is:
plink.exe -ssh user#IP -pw PW "shell nstcpdump.sh -s0 -U -w - not port 22 and not host 127.0.0.1" | "C:\Program Files\Wireshark\wireshark" -i -
This will fail since when executing the command on the remote system, this (custom) shell will output "Done" before sending data. I tried to find out a way to remove the "Done" message from the shell but doesn't appear to be any.
So I came up with this (added findstr -V):
plink.exe -ssh user#IP -pw PW "shell nstcpdump.sh -s0 -U -w - not port 22 and not host 127.0.0.1" | findstr -V "Done" | "C:\Program Files\Wireshark\wireshark" -i -
This works more or less fine since I will get some errors and the live capture will stop. I believe it might have something to do with the buffers, but I'm not sure.
Does anyone know of any other method of removing/bypassing the first bytes/chars of the output from plink/remote shell?
[edit]
as asked, nstcpdump.sh is a wrapper for tcpdump. as mentioned before, this system is highly customized. nstcpdump.sh code:
root#hostname# cat /netscaler/nstcpdump.sh
#!/bin/sh
# piping the packet trace to the tcpdump
#
# FILE: $Id: //depot/main/rs_120_56_14_RTM/usr.src/netscaler/scripts/nstcpdump.sh#1 $
# LAST CHECKIN: $Author: build $
# $DateTime: 2017/11/30 02:14:38 $
#
#
# Options: any TCPDUMP options
#
TCPDUMP_PIPE=/var/tmp/tcpdump_pipe
NETSCALER=${NETSCALER:-`cat /var/run/.NETSCALER`}
[ -r ${NETSCALER}/netscaler.conf ] && . ${NETSCALER}/netscaler.conf
TIME=${TIME:-3600}
MODE=${MODE:-6}
STARTCMD="start nstrace -size 0 -traceformat PCAP -merge ONTHEFLY -filetype PIPE -skipLocalSSH ENABLED"
STOPCMD="stop nstrace "
SHOWCMD="show nstrace "
NSCLI_FILE_EXEC=/netscaler/nscli
NSTRACE_OUT_FILE=/tmp/nstrace.out
NS_STARTTRACE_PIDFILE=/tmp/nstcpdump.pid
TRACESTATE=$(nsapimgr -d allvariables | grep tracestate | awk '{ print $2}')
trap nstcpdump_exit 1 2 15
nstcpdump_init()
{
echo "##### WARNING #####"
echo "This command has been deprecated."
echo "Please use 'start nstrace...' command from CLI to capture nstrace."
echo "trace will now start with all default options"
echo "###################"
if [ ! -d $NSTRACE_DIR ]
then
echo "$NSTRACE_DIR directory doesn't exist."
echo "Possible reason: partition is not mounted."
echo "Check partitions using mount program and try again."
exit 1
fi
if [ ! -x $NSCLI_FILE_EXEC ]
then
echo "$NSCLI_FILE_EXEC binary doesn't exist"
exit 1
fi
if [ -e $NSTRACE_OUT_FILE ]
then
rm $NSTRACE_OUT_FILE
echo "" >> $NSTRACE_OUT_FILE
fi
}
nstcpdump_start_petrace()
{
sleep 0.5;
$NSCLI_FILE_EXEC -U %%:.:. $STARTCMD >/tmp/nstcpdump.sh.out
rm -f ${NS_STARTTRACE_PIDFILE}
}
nstcpdump_start()
{
# exit if trace is already running
if [ $TRACESTATE -ne 0 ]
then
echo "Error: one instance of nstrace is already running"
exit 2
fi
nstcpdump_start_petrace &
echo $! > ${NS_STARTTRACE_PIDFILE}
tcpdump -n -r - $TCPDUMPOPTIONS < ${TCPDUMP_PIPE}
nstcpdump_exit
exit 1
}
nstcpdump_exit()
{
if [ -f ${NS_STARTTRACE_PIDFILE} ]
then
kill `cat ${NS_STARTTRACE_PIDFILE}`
rm ${NS_STARTTRACE_PIDFILE}
fi
$NSCLI_FILE_EXEC -U %%:.:. $STOPCMD >> /dev/null
exit 1
}
nstcpdump_usage()
{
echo `basename $0`: utility to view/save/sniff LIVE packet capture on NETSCALER box
tcpdump -h
echo
echo NOTE: tcpdump options -i, -r and -F are NOT SUPPORTED by this utility
exit 0
}
########################################################################
while [ $# -gt 0 ]
do
case "$1" in
-h )
nstcpdump_usage
;;
-i )
nstcpdump_usage
;;
-r )
nstcpdump_usage
;;
-F )
nstcpdump_usage
;;
esac
break;
done
TCPDUMPOPTIONS="$#"
check_ns nstcpdump
#nstcpdump_init
#set -e
if [ ! -e ${TCPDUMP_PIPE} ]
then
mkfifo $TCPDUMP_PIPE
if [ $? -ne 0 ]
then
echo "Failed creating pipe [$TCPDUMP_PIPE]"
exit 1;
fi
fi
nstcpdump_start
Regards

notify-send from within a bash script

I'd like to use notify-send from within a bash script that is running in the background to inform the user about the progress of the script. More specifically this is a script that automagically runs when a USB flash drive is inserted and runs a scan with ClamAV.
Specifically at line 30 and line 66. So far, I'm not having any luck. Can someone give me some advice/help? Thanks.
#!/bin/bash
#doOnUSBinsert_0.2.sh
#Author : Totti
# Make it executable by running 'sudo chmod x doOnUSBinsert_0.2.sh'
if ! [ -f /etc/udev/rules.d/80-doOnUSBinsert.rules ]
then # rule not added
cp "$0" /usr/bin/doOnUSBinsert
chmod u x /usr/bin/doOnUSBinsert
# echo 'SUBSYSTEM=="usb", ACTION=="add", RUN ="/path/to/script.sh"' | sudo tee /etc/udev/rules.d/80-clamscan.rules
echo 'SUBSYSTEM=="usb", ACTION=="add", RUN ="/usr/bin/doOnUSBinsert & "' | tee /etc/udev/rules.d/80-doOnUSBinsert.rules
if [ $? -eq 0 ]
then
echo 'Rule Successfully added. See file "/usr/bin/doOnUSBinsert" if you wish to edit the command'
exit 0
else
echo 'ERROR while adding rule'
exit 1
fi
fi
lfile="/tmp/doOnUSBinsert.log" # udev
lfile2="/tmp/clamscanFromUdev.log" # clamscan
lfile3="/tmp/doOnUSBinsert_mount.log" # mount
notify-send "USB SCAN ON INSERT" "Currently scanning with ClamAV"
main ()
{
sleep 12 # let the partitions to mount
#cat /proc/$$/environ | tr '�' 'n' >> /tmp/udevEnvirn.txt
echo "found $ID_SERIAL" >> "$lfile"
cat /etc/mtab | grep "^$part_c" >> "$lfile.3"
if [ "$ID_SERIAL"x = 'x' ]
then
echo "Exiting on empty ID_SERIAL" >> "$lfile"
exit 1
fi
#Eg: ID_SERIAL --> /dev/disk/by-id/usb-sandisk....42343254343543
#i=0
echo 'searching partitions' >> "$lfile"
for partitionPath in $( find /dev/disk/by-id/ -name "*$ID_SERIAL*part*" )
do
echo "current partition = $partitionPath" >> "$lfile"
# part[i ]="$( readlink -f "$partition" )" # Eg Output: /dev/sdb1 , /dev/sdb2
part_c="$( readlink -f $partitionPath )"
mpoint="$( cat /etc/mtab | grep "^$part_c" | awk '{print $2}' )"
echo "partitionPath= $partitionPath, part = $part_c, mountpoint= $mpoint" >> "$lfile"
echo "Scaning --> $mpoint" >> "$lfile.2"
############################################
clamscan -r --bell "$mpoint"/* >> "$lfile.2"
#############################################
done
}
notify-send "USB SCAN ON INSERT" "Finished scanning with ClamAV"
main &
echo ______________________________________ >> "$lfile"
exit 0
I'm pretty new to the linux world, but while looking for a solution for a similar project I found THIS
Tip: An overview on the available icons can be found here. To send
desktop notification from a background script running as root (replace
X_user and X_userid with the user and userid running X respectively):
sudo -u X_user DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/X_userid/bus notify-send 'Hello world!' 'This is an example notification.'
Hope this will help others.
Depending on how you are running the script it may not have access to the display variable. Try running export DISPLAY=:0.0 prior to the command.
If you are running the script as a different user, ie root, then you may also need to run it as su - <logged in user> -c notify-send ... (I usually don't need to do this, but I remember having to at one point - but I cant recall which distro or version I was on at the time.)

Crontab will not execute .sh but crontab will execute a command

This issue is currently driving me nuts.
I setup a crontab with sudo crontab -e
The contents are 1 * * * * /home/bolte/bin/touchtest.sh
The contents of that file are:
#!/bin/bash
touch /home/bolte/bin/test.log
It creates the file. But the below script will not run.
#!/bin/bash
# CHANGE THESE
auth_email="11111111#live.co.uk"
auth_key="11111111111111111" # found in cloudflare
account settings
zone_name="11111.io"
record_name="11111.bolte.io"
# MAYBE CHANGE THESE
ip=$(curl -s http://ipv4.icanhazip.com)
ip_file="/home/bolte/ip.txt"
id_file="/home/bolte/cloudflare.ids"
log_file="/home/bolte/cloudflare.log"
# LOGGER
log() {
if [ "$1" ]; then
echo -e "[$(date)] - $1" >> $log_file
fi
}
# SCRIPT START
log "Check Initiated"
if [ -f $ip_file ]; then
old_ip=$(cat $ip_file)
if [ $ip == $old_ip ]; then
echo "IP has not changed."
exit 0
fi
fi
if [ -f $id_file ] && [ $(wc -l $id_file | cut -d " " -f 1) == 2 ]; then
zone_identifier=$(head -1 $id_file)
record_identifier=$(tail -1 $id_file)
else
zone_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" -H "X-Auth-E$
record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_record$
echo "$zone_identifier" > $id_file
echo "$record_identifier" >> $id_file
fi
update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_ident$
[ Read 55 lines (Warning: No write permission) ]
^G Get Help ^O Write Out ^W Where Is ^K Cut Text ^J Justify ^C Cur Pos ^Y Prev Page
^X Exit ^R Read File ^\ Replace ^U Uncut Text ^T To Linter ^_ Go To Line ^V Next Page
I've been trying to troubleshoot why this code will not run every minute, there doesn't seem to be any output in the same folder as the script, which is located at /home/bolte/cloudflare-update-record.sh
Ok so the answer to this was, I was editing crontab with sudo, and the files were located in my users home folder. This is why they weren't working. Resolved my own issue.
If you have this issue just use $ crontab -e rather than sudo crontab -e, and specify full paths for your file outputs, unless you are putting the proper path variables in your script.

Bash sub script redirects input to /dev/null mistakenly

I'm working on a script to automate the creation of a .gitconfig file.
This is my main script that calls a function which in turn execute another file.
dotfile.sh
COMMAND_NAME=$1
shift
ARG_NAME=$#
set +a
fail() {
echo "";
printf "\r[${RED}FAIL${RESET}] $1\n";
echo "";
exit 1;
}
set -a
sub_setup() {
info "This may overwrite existing files in your computer. Are you sure? (y/n)";
read -p "" -n 1;
echo "";
if [[ $REPLY =~ ^[Yy]$ ]]; then
for ARG in $ARG_NAME; do
local SCRIPT="~/dotfiles/setup/${ARG}.sh";
[ -f "$SCRIPT" ] && echo "Applying '$ARG'" && . "$SCRIPT" || fail "Unable to find script '$ARG'";
done;
fi;
}
case $COMMAND_NAME in
"" | "-h" | "--help")
sub_help;
;;
*)
CMD=${COMMAND_NAME/*-/}
sub_${CMD} $ARG_NAME 2> /dev/null;
if [ $? = 127 ]; then
fail "'$CMD' is not a known command or has errors.";
fi;
;;
esac;
git.sh
git_config() {
if [ ! -f "~/dotfiles/git/gitconfig_template" ]; then
fail "No gitconfig_template file found in ~/dotfiles/git/";
elif [ -f "~/dotfiles/.gitconfig" ]; then
fail ".gitconfig already exists. Delete the file and retry.";
else
echo "Setting up .gitconfig";
GIT_CREDENTIAL="cache"
[ "$(uname -s)" == "Darwin" ] && GIT_CREDENTIAL="osxkeychain";
user " - What is your GitHub author name?";
read -e GIT_AUTHORNAME;
user " - What is your GitHub author email?";
read -e GIT_AUTHOREMAIL;
user " - What is your GitHub username?";
read -e GIT_USERNAME;
if sed -e "s/AUTHORNAME/$GIT_AUTHORNAME/g" \
-e "s/AUTHOREMAIL/$GIT_AUTHOREMAIL/g" \
-e "s/USERNAME/$GIT_USERNAME/g" \
-e "s/GIT_CREDENTIAL_HELPER/$GIT_CREDENTIAL/g" \
"~/dotfiles/git/gitconfig_template" > "~/dotfiles/.gitconfig"; then
success ".gitconfig has been setup";
else
fail ".gitconfig has not been setup";
fi;
fi;
}
git_config
In the console
$ ./dotfile.sh --setup git
[ ?? ] This may overwrite existing files in your computer. Are you sure? (y/n)
y
Applying 'git'
Setting up .gitconfig
[ .. ] - What is your GitHub author name?
Then I cannot see what I'm typing...
At the bottom of dotfile.sh, I redirect any error that occurs during my function call to /dev/null. But I should normally see what I'm typing. If I remove 2> /dev/null from this line sub_${CMD} $ARG_NAME 2> /dev/null;, it works!! But I don't understand why.
I need this line to prevent my script to echo an error in case my command doesn't exists. I only want my own message.
e.g.
$ ./dotfile --blahblah
./dotfiles: line 153: sub_blahblah: command not found
[FAIL] 'blahblah' is not a known command or has errors
I really don't understand why the input in my sub script is redirected to /dev/null as I mentioned only stderr to be redirected to /dev/null.
Thanks
Do you need the -e option in your read statements?
I did a quick test in an interactive shell. The following command does not echo characters :
read -e TEST 2>/dev/null
The following does echo the characters
read TEST 2>/dev/null

How would I go about reading the log to check if a command is finished executing before running another command?

This is a bash script I wrote that automatically trims all the worlds for a minecraft server at an interval specified in crontab. It will execute the "/wb $WORLD trim" command and the "/wb trim confirm" command on each world, one by one, where $WORLD is the world that it is currently working on. By loading each world from a list of files into a for loop, it will trim each world sequentially. Right now, since world trimming can take a varying amount of time, I'm unsure how to tell it to not stop if it isn't done yet, since only 30 seconds are allocated to each world. I figure that reading the log file to get the status of the command might work, but I'm not sure exactly how to go about doing so. I figure something like "grep" and "awk" might do the job, but I'm not sure whether that will work, as this seems to be a pretty complicated roadblock. Any ideas? I have the part of a log file that it prints while trimming a world posted here on pastebin. Also, is there anything besides that I could do to improve this script? I've only been writing code for a couple of months, and not that often at that, so I'm new to programming/scripting in general.
#!/bin/bash
# Title: World Border Trim Automator
# Author: Jonathan Bondhus
######### CONFIG STARTS HERE #########
# Location of the init script
INIT_SCRIPT="/etc/init.d/minecraft"
# Name to use for the screen instance
SCREEN="minecraft"
# User that should run the server
USERNAME="minecraft"
# Path to minecraft server directory
MCPATH="/home/${USERNAME}/minecraft"
# Where the worlds are located on the disk
WORLDSTORAGE="${MCPATH}/worlds"
######### CONFIG ENDS HERE #########
## Start of script, don't edit anything below this line unless you know what you are doing
as_user() {
if [ $ME == $USERNAME ] ; then
bash -c "$1"
else
su $USERNAME -s /bin/bash -c "$1"
fi
}
my_trim() {
a=1
for NAME in $(ls $WORLDSTORAGE)
do
if [ -d $WORLDSTORAGE/$NAME ]
then
WORLDNAME[$a]=$NAME
a=$a+1
# Run the /wb trim command
echo "Running /wb $NAME trim..."
as_user "screen -p 0 -S $SCREEN -X eval 'stuff \"wb $NAME trim\"\015'"
sleep 2 # Wait 2 seconds
clear
echo "Running /wb trim confirm..."
as_user "screen -p 0 -S $SCREEN -X eval 'stuff \"wb trim confirm\"\015'"
sleep 1
clear
echo "Waiting 30 seconds for trim to complete..."
sleep 30 # Wait 30 seconds
fi
done
}
my_is_running(){
# Checks for the minecraft servers screen session
# returns true if it exists.
if ps ax | grep -v grep | grep "$SCREEN $INVOCATION" > /dev/null
then
return 0
fi
return 1
}
my_main(){
ME=`whoami` # Sets $ME to equal the current user's username
my_is_running
if my_is_running
then
my_trim
else
echo "Server is not running... Starting..."
my_as_user "$INIT_SCRIPT start"
wait 100
fi
}
my_as_user() {
if [ $me == $username ] ; then
bash -c "$1"
else
su $USERNAME -s /bin/bash -c "$1"
fi
}
my_main
exit 0
Any reason you're running 'stuff' inside 'screen'?
If you removed it, 'stuff' will execute synchronously, and return after the command completes.
my_trim() {
a=1
for NAME in $(ls $WORLDSTORAGE)
do
if [ -d $WORLDSTORAGE/$NAME ]
then
WORLDNAME[$a]=$NAME
a=$a+1
# Run the /wb trim command
echo "Running /wb $NAME trim..."
as_user "stuff \"wb $NAME trim\"\015" # will block here until stuff returns
#sleep 2 # no reason this any more
clear
echo "Running /wb trim confirm..."
as_user "stuff \"wb trim confirm\"\015"
#sleep 1
clear
echo "Done"
#sleep 30
fi
done
}
In the following it is assumed that the variable MCLOGFILE is set to the log file name.
my_trim() {
cd $WORLDSTORAGE
for NAME in *
do
if [ -d $NAME ]
then
# Run the /wb trim command
echo "Running /wb $NAME trim..."
as_user "screen -p 0 -S $SCREEN -X eval 'stuff \"wb $NAME trim\"\015'"
sleep 2 # Wait 2 seconds
clear
echo "Running /wb trim confirm..."
kill `((tail -f $MCLOGFILE -n0& echo $! >&3
as_user "screen -p 0 -S $SCREEN -X eval 'stuff \"wb trim confirm\"\015'"
sleep 1
clear >&2
echo "Waiting for trim to complete..." >&2
)|grep -q 'task successfully completed!'
) 3>&1|head -1
`
fi
done
}
The kill stuff is there because otherwise tail would continue to run in the background until a line after the one with task successfully completed! were written to the log file.

Resources