why ECHO does not come up? - linux

I have this shell :
===
#!/bin/sh -e
LogFile=/home/pi/logs/prova.log # log file
test -e $LogFile || touch $LogFile # create it if non existent
echo "(1) ======== ======== ======== Inici de PROVA.SH" >> $LogFile
echo "(2) ping 1.2.3.4" >> $LogFile
# ping 1.2.3.4 -W 3 -c 2 >> $LogFile
echo "(3) start APP" >> $LogFile
echo "LOG file is" $LogFile
exit 0
===
The output is
1) one line to screen
2) three lines to file
But if the 8th line (ping 1.2.3.4) is un-commented,
the "echo's" after the 8th line do not get written,
neither to the screen, neither to the file.
I need to understand why, and how to solve it.
I guess is something related to the fact that "ping" runs in another shell,
so the "echo's" write there.
But I don't know how to fix it.
Any pointer or URL to documentation is welcome.
Sebastian.

ping -W 3 -c 2 1.2.3.4 >> $LogFile
Put the IP/Hostname after the ping options.

Most likely:
ping fails because of wrong order of arguments: destination should be last.
Your script runs with -e so it exits at first error, so it stops after ping fails.
You don't redirect standard error for ping : the error message is lost
If you remove -e, ping still fails, but the script continues, executes the last 2 lines and you get their output (but you do not get from ping because that goes to stderr)
Solution, 2 changes:
ping -W 3 -c 2 1.2.3.4 2>&1 >> $LogFile
^^^^^^^ ^^^^
I.P as last argument & Redirect stderr to stdout before redirecting to file

Related

Linux - Cat command doesn't maintain the file format

I have a Linux script that generates an HTML file with various outputs for various Linux commands.
Here is one of the outputs that creates an intrf.txt. I generated this file using this command
ip link show|sed '=;G'>intrf.txt
I did that as I want the lines of file to have line space between.
If I do the cat intrf.txt command on my shell I can see indeed the line spacing. If I run the script with the function below I see all lines of this file on my browser, but concatenated with no space between.
Maybe this is something simple, but I cannot figure it out.
function net_ifconfig
{
echo -e "GET http://google.com HTTP/1.0\n\n" | nc google.com 80 > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "<h2 style="background-color:#00FF00"><font size="5"> CHECK 2. LIST OF AVAILABLE INTERFACE</h2>"
ip link show|sed '=;G'>intrf.txt
cat intrf.txt
else
echo "CHECK 1. INTERNET IF OFFLINE"
echo "<h2 style="background-color:#FF0000"><font size="5"> INTERNET IS NOT CONNECTED</h2>"
fi
}
Seems if I put the command between pre tags it works.
echo "<pre>"
ip link show|sed '=;G'>intrf.txt
cat intrf.txt
echo "</pre>"

My first Bash script does not look so efficient

This is my first bash script using some resources I found online. I think there is a better way to write this perhaps using some other form of conditionals (if then vs control operators).
It is a script that basically checks if a host is up or down (check if it is ping-able). You dump all the ip addresses you want into a file, then run the script calling on the file. The text file looks like this:
8.8.8.8
4.8.8.8
4.4.4.4
127.0.0.1
The actual script looks like this. Is the 2>&1 necessary because it worked without. I had to play around with the brackets a lot.
#!/bin/bash
while read line
do
A=$(ping -c 1 $line)
((echo $A | grep "64 bytes") > /dev/null 2>&1 && (echo "UP - "$line)) || echo "DOWN - "$line
done < $1
Thank you!
You can do it entirely without brackets:
while read -r address; do
ping -c 1 $address >/dev/null 2>&1 && echo "UP - $address" || echo "DOWN - $address"
done < file
The >/dev/null 2>&1 redirects both STDOUT and STDERR to /dev/null meaning that whatever ping outputs won't be printed to your terminal.
You can then use the && and || operators to echo a message in case of success (ping exits with 0) or failure (ping exits with >0)
You could use if..then..else if you prefer:
while read -r address; do
if ping -c 1 $address > /dev/null 2>&1; then
echo "UP - $address"
else
echo "DOWN - $address"
fi
done < file
arco444 has the right answer. Some other notes
with the form A && B || C, if A succeeds then B executes; if B fails, C will execute. That will not occur for if A; then B; else C; fi
proper indentation is extremely helpful to identify errors (none here, but in general)
Use better variable names: $ip is more meaningful than $line
variables go inside the quotes
parentheses introduce subshells, which will reduce performance. Use only when necessary

Grep not working in script but on console

I have a problem with a script. I have a voltage meter connected to a serial USB device(ttyUSB1).
The smart meter needs an initial sequence and shortly followed by a second command to give all of it's information. That works fine. 1.8.0*00(000898.46) for example comes in this is the line I am interested in. The number in brackets is the kWh number i want. If i open a second terminal and do a cat /dev/ttyUSB1 it works fine and i can see the information coming in. After 4 to 5 seconds the line I want comes in. But the script is not working. If i start a script in one terminal it keeps waiting. Grep is not finishing. If I start it in a second terminal then the first terminal gets finished. Or just the grep 1.8.0 /dev/ttyUSB1 -m1 in another terminal works but not in the script.
I tried different methos with read and so none worked. To be honest i don't understand much of scripting and always succeed somehow but here nothings helped :(
Please help. Thank you!
Arne
here the script:
#! /bin/bash
echo start
echo $'\x2f\x3f\x21\x0d' > /dev/ttyUSB1
sleep 1
echo ask
echo $'\x06\x30\x30\x30\x0d' > /dev/ttyUSB1
echo wait
grep 1.8.0 /dev/ttyUSB1 -m1
echo end
You can try creating a file with voltimeter's output and grep from that file:
#! /bin/bash
dev=/dev/ttyUSB1
file=/tmp/testfile
(tail -f $dev | tee $file) & # let's continuously copy in background
echo start
echo $'\x2f\x3f\x21\x0d' > $dev
sleep 1
echo ask
echo $'\x06\x30\x30\x30\x0d' > $dev
echo wait
grep 1.8.0 $file # lets get the info from the file instead
echo end
sleep 1
exit

How to set up an automatic (re)start of a background ssh tunnel

I am a beginner user of linux, and also quite newbie at ssh and tunnels.
Anyway, my goal is to maintain a ssh tunnel open in background.
In order to do that, I wrote the following batch that I then added into crontab (the batch is automatically processed every 5 minutes during workdays and from 8am to 9pm).
I read in some other thread in stackoverflow that one should use autossh that will ensure the ssh will always be ok through a recurrent check. So did I....
#!/bin/bash
LOGFILE="/root/Tunnel/logBatchRestart.log"
NOW="$(date +%d/%m/%Y' - '%H:%M)" # date & time of log
if ! ps ax | grep ssh | grep tunnelToto &> /dev/null
then
echo "[$NOW] ssh tunnel not running : restarting it" >> $LOGFILE
autossh -f -N -L pppp:tunnelToto:nnnnn nom-prenom#193.xxx.yyy.zzz -p qqqq
if ! ps ax | grep ssh | grep toto &> /dev/null
then
echo "[$NOW] failed starting tunnel" >> $LOGFILE
else
echo "[$NOW] restart successfull" >> $LOGFILE
fi
fi
My problem is that sometimes the tunnel stops working, although every thing looks ok (ps ax | grep ssh > the result shows the two expected tasks : autossh main task and the ssh tunnel itself). I actually know about the problem cause the tunnel is used by a third party software that triggers an error as soon as the tunnel is no more responding.
SO I am wondering how I should improve my batch in order It will be able to check the tunnel and restart it if it happens to be dead. I saw some ideas in there, but it was concluded by the "autossh" hint... which I already use. Thus, I am out of ideas... If any of you have, I'd gladly have a look at them!
Thanks for taking interest in my question, and for your (maybe) suggestions!
Instead of checking the ssh process with ps you can do the following trick
create script, that does the following and add it to your crontab via crontab -e
#!/bin/sh
REMOTEUSER=username
REMOTEHOST=remotehost
SSH_REMOTEPORT=22
SSH_LOCALPORT=10022
TUNNEL_REMOTEPORT=8080
TUNNEL_LOCALPORT=8080
createTunnel() {
/usr/bin/ssh -f -N -L$SSH_LOCALPORT:$REMOTEHOST:SSH_REMOTEPORT -L$TUNNEL_LOCALPORT:$REMOTEHOST:TUNNEL_REMOTEPORT $REMOTEUSER#$REMOTEHOST
if [[ $? -eq 0 ]]; then
echo Tunnel to $REMOTEHOST created successfully
else
echo An error occurred creating a tunnel to $REMOTEHOST RC was $?
fi
}
## Run the 'ls' command remotely. If it returns non-zero, then create a new connection
/usr/bin/ssh -p $SSH_LOCALPORT $REMOTEUSER#localhost ls >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo Creating new tunnel connection
createTunnel
fi
In fact, this script will open two ports
port 22 which will be used to check if the tunnel is still alive
port 8080 which is the port you might want to use
Please check and send me further questions via comments
(I add this as an answer since there is not enough room for it un a comment)
Ok, I managed to make the batch run to launch the ssh tunnel (I had to specify my hostname instead of localhost in order it could be triggered) :
#!/bin/bash
LOGFILE="/root/Tunnel/logBatchRedemarrage.log"
NOW="$(date +%d/%m/%Y' - '%H:%M)" # date et heure du log
REMOTEUSER=username
REMOTEHOST=remoteHost
SSH_REMOTEPORT=22
SSH_LOCALPORT=10022
TUNNEL_REMOTEPORT=12081
TUNNEL_SPECIFIC_REMOTE_PORT=22223
TUNNEL_LOCALPORT=8082
createTunnel() {
/usr/bin/ssh -f -N -L$SSH_LOCALPORT:$REMOTEHOST:$SSH_REMOTEPORT -L$TUNNEL_LOCALPORT:$REMOTEHOST:$TUNNEL_REMOTEPORT $REMOTEUSER#193.abc.def.ghi -p $TUNNEL_SPECIFIC_REMOTE_PORT
if [[ $? -eq 0 ]]; then
echo [$NOW] Tunnel to $REMOTEHOST created successfully >> $LOGFILE
else
echo [$NOW] An error occurred creating a tunnel to $REMOTEHOST RC was $? >> $LOGFILE
fi
}
## Run the 'ls' command remotely. If it returns non-zero, then create a new connection
/usr/bin/ssh -p $SSH_LOCALPORT $REMOTEUSER#193.abc.def.ghi ls >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo [$NOW] Creating new tunnel connection >> $LOGFILE
createTunnel
fi
However, I got some immediate message (below) when the tunnel is running and when cron tries to lauch the batch again... sounds like it cannot listen to it. Also since I need some time to get a proof , I can't say yet it will successfully restart if the tunnel is out.
Here's the response to the second start of the batch.
bind: Address already in use channel_setup_fwd_listener: cannot listen
to port: 10022 bind: Address already in use
channel_setup_fwd_listener: cannot listen to port: 8082 Could not
request local forwarding.

Continue to grep for traceroute result with bash

Every night I go through the same process of checking failover systems for our T1's. I essentially go through the following process:
Start the failover process.
traceroute $server;
Once I see it's failed over, I verify that connections work by SSHing into a server.
ssh $server;
Then once I see it works, I take it off of failover.
So what I want to do is to continually run a traceroute until I get a certain result, then run a SSH command.
Put your list of successful messages in a file (omit the variable lines and fractions of the line, and use a ^ to identify the start of the line, as such:)
patterns.list:
^ 7 4.68.63.165
^ 8 4.68.17.133
^ 9 4.79.168.210
^10 216.239.48.108
^11 66.249.94.46
^12 72.14.204.99
Then a simple while loop:
while ! traceroute -n ${TARGET} | grep -f patterns.list
do
sleep 5 # 5 second delay between traceroutes, for niceness.
done
ssh ${DESTINATION}
Use traceroute -n to generate the output so you don't get an IP address that resolves one time, but and a name the next, resulting in a false positive.
I think you could be better off using ping command to verify server's accessability than traceroute.
It is easy to check for return status of ping command without using any grep at all:
if [ ping -c 4 -n -q 10.10.10.10 >/dev/null 2>& ]; then
echo "Server is ok"
else
echo "Server is down"
fi
If you want to do it continually in a loop, try this:
function check_ssh {
# do your ssh stuff here
echo "performing ssh test"
}
while : ; do
if [ ping -c 4 -n -q 10.10.10.10 >/dev/null 2>& ]; then
echo "Server is ok"
check_ssh
else
echo "Server is down"
fi
sleep 60
done

Resources