heredoc failing when piped into ssh - bash

I am trying to do commands via ssh using a heredoc. when I use the 'EOF' style:
result=$(ssh $quiet -T ${G_IPAddressBase}${G_TGP} <<- 'EOF'
set pid=`ps -ef | grep TestPatterns | egrep -v 'grep|tail|vi|csh' | gawk '{print $2}'`
if ( "$pid" != "" ) then
echo "TestPatterns ($pid) terminated"
kill $pid
else
echo "TestPatterns down already"
endif
EOF
)
everything works as excepted because the $ and qrave marks are not expanded out.
But if I want to include local variables and use \ to stop the variable from being resolved, the \ does not stop the $ variable from resolving as expected.
result=$(ssh $quiet -T ${G_IPAddressBase}${G_TGP} <<- EOF
set pid=\`ps -ef | grep $mytaskName | grep '\/bin\/bash' | gawk '{print \$2}'\`
if ( "\$pid" == "" ) then
echo "ERROR: $mytaskName cored"
else
if ( -f "$mytaskLogpath" ) then
set agent1Done=1
else
echo "ERROR: $mytaskName didn't make a report file"
endif
endif
EOF
)
The pid is being set to blank because its looks like this on the remote side:
set pid=`ps -ef | grep TestPatterns | egrep -v 'grep|tail|vi|csh' | gawk '{print }'`
Everything that I have read says this should not be happening. If I cat << EOF > /tmp/command.csh the heredoc to a file the commands match what I expect on the remote box and work as expected.
This script is in bash, but the default shell is tcsh and that's what the remote is running so its not because the csh commands are running in a bash window on the remote login.
Any ideas what I am doing wrong?

Related

System Variable set in bash not sticking after i go to an IF statement

apacherelease=$(curl -s "https://httpd.apache.org" | grep Released | awk '{print $4}' | perl -p -e 's/2.4.54/2.4.54-1/g') &&
apacheinstallversion=$(dnf list installed | grep httpd.x86_64|awk '{print $2}') &&
echo $apacherelease
echo $apacheinstallversion
if test "$apacheinstallversion" = "$apacherelease"; then
: variables are the same
else
: variables are different
fi
`
If I run the commands to set variable directly from the command line instead of a script the variables stick however in the script they disappear the moment I move to the if statement.
Any input would extremely help!
Corrected version:
apacherelease=$(curl -s "https://httpd.apache.org" | grep Released | awk '{print $4}' | perl -p -e 's/2.4.54/2.4.54-1/g') &&
apacheinstallversion=$(dnf list installed | grep httpd.x86_64 | awk '{print $2}')
echo "$apacherelease"
echo "$apacheinstallversion"
if [[ $apacheinstallversion == $apacherelease ]]; then
echo "variables are the same"
else
echo "variables are different" >&2
fi
use the full featured bash test [[
use == instead of =

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.

Bash is redirecting output from command only after script has finished

Context
Got a daft script that checks a process is running on a group of hosts, like a watchdog, as I say it's a daft script so bear in mind it isn't 'perfect' by scripting standards
Problem
I've ran bash -x and can see that the script finishes its first check without actually redirecting the output of the command to the file which is very frustrating, it means each host is actually being evaluated to the last hosts output
Code
#!/bin/bash
FILE='OUTPUT'
for host in $(cat /etc/hosts | grep webserver.[2][1-2][0-2][0-9] | awk {' print $2 ' })
do ssh -n -f $host -i <sshkey> 'ps ax | grep myprocess | wc -l' > $FILE 2> /dev/null
cat $FILE
if grep '1' $FILE ; then
echo "Process is NOT running on $host"
cat $FILE
else
cat $FILE
echo "ALL OK on $host"
fi
cat $FILE
done
Script traceback
++ cat /etc/hosts
++ awk '{ print $2 }'
++ grep 'webserver.[2][1-2][0-2][0-9]'
+ for host in '$(cat /etc/hosts | grep webserver.[2][1-2][0-2][0-9] | awk {'\'' print $2 '\''})'
+ ssh -n -f webserver.2100 -i <omitted> 'ps ax | grep myprocess | wc -l'
+ cat OUTPUT
+ grep 1 OUTPUT
+ cat OUTPUT
+ echo 'ALL OK on webserver.2100'
ALL OK on webserver.2100
+ cat OUTPUT
+ printf 'webserver.2100 checked \n'
webserver.2100 checked
+ for host in '$(cat /etc/hosts | grep webserver.[2][1-2][0-2][0-9] | awk {'\'' print $2 '\''})'
+ ssh -n -f webserver.2101 -i <omitted> 'ps ax | grep myprocess | wc -l'
+ cat OUTPUT
2
+ grep 1 OUTPUT
+ cat OUTPUT
2
+ echo 'ALL OK on webserver.2101'
ALL OK on webserver.2101
+ cat OUTPUT
2
+ printf 'webserver.2101 checked \n'
webserver.2101 checked
Issue
As you can see, it's registering nothing for the first host, then after it is done, it's piping the data into the file, then the second host is being evaluated for the previous hosts data...
I suspect its to do with redirection, but in my eyes this should work, it doesn't so it's frustrating.
I think you're assuming that ps ax | grep myprocess will always return at least one line (the grep process). I'm not sure that's true. I'd rewrite that like this:
awk '/webserver.[2][1-2][0-2][0-9]/ {print $2}' /etc/hosts | while IFS= read -r host; do
output=$( ssh -n -f "$host" -i "$sshkey" 'ps ax | grep "[m]yprocess"' )
if [[ -z "$output" ]]; then
echo "Process is NOT running on $host"
else
echo "ALL OK on $host"
fi
done
This trick ps ax | grep "[m]yprocess" effectively removes the grep process from the ps output:
the string "myprocess" matches the regular expression "[m]yprocess" (that's the running "myprocess" process), but
the string "[m]yprocess" does not match the regular expression "[m]yprocess" (that's the running "grep" process)

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

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