I am trying to write a small script in bash. My target is that a Phone Call on my FritzBox will mute or pause my TV.
I get the information of a call via telnet (telnet fritz.box 1012) on my RaspberryPi and if there is coming a phone call in I get this output:
24.08.15 14:03:05;RING;0;017mobilephonenumber;49304myhomenumber;SIP0;
The only Part that is every time the same is the RING before the calling number. What I need is a script that checks the output of the telnet and if in the telnet output is a ring than execute an action in my case i just need to do a http request on an internal site or start another script.
This is what I have tried is this:
#!/bin/bash
#string='echo "My string"'
string=$(telnet –e p fritz.box 1012)
for reqsubstr in 'alt' 'RING';do
if [ -z "${string##*$reqsubstr*}" ] ;then
echo "String '$string' contain substring: '$reqsubstr'."
else
echo "String '$string' don't contain substring: '$reqsubstr'."
fi
done
But I don`t get the output of my telnet session into the string. Anyone who can help me?
After you latest comment, and reading your question again, I think we can go for something simpler based on nc (netcat).
Let assume we create a bash script called action.sh
#!/bin/bash
while true;
do
read logline
for substr in 'alt' '\;RING\;'
do
if [[ "$logline" = *${substr}* ]]; then
echo "Got a match"
fi
done
done
Make the script executable, chmod +x action.sh, then start it with nc as follow:
nc -l fritz.box 1012 | ./action.sh
It will listen infinitely for incoming traffic from the box and should act as you want. I don't have your box obviously and I tested by starting it as nc -l 127.0.0.1 12000 and then provided input via telnet 127.0.0.1 12000, providing your RING sample. It seems to work.
$ nc -l 127.0.0.1 12000 | ./action.sh
Got a match
017mobilephonenumber
Got a match
017mobilephonenumber
Would this be more acceptable to you ? without expect (I am not an expect wizard anyway).
I hope this answer will help you more.
do you have access to expect? It is meant exactly for such kind of scenario. man expect is your friend, and I found a fair tutorial via google. If you google for modem expect you can find sample script for such scenario (I can find some for FritzBox too but not sure it's the same box as yours). I haven't used it in ages, though.
Here my short conclusion:
To see incomming calls on your FritzBox you can simply execute:
telnet fritz.box 1012
in your terminal.
The output should look like that:
24.08.15 14:03:05;RING;0;017mobilephonenumber;49304myhomenumber;SIP0;
I my case I want the execute an command the mutes my TV.
Here are the instructions how I controll my TV via Web/RaspberryPi (Philips Harmony Hub) if some one is interested.
To execute a command on an incomming call create a script called action.sh
#!/bin/bash
while true;
do
read logline
for substr in 'alt' '\;RING\;'
do
if [[ "$logline" = *${substr}* ]]; then
echo "Got a match"
#here you can put the command you want to execute on an incoming call
fi
done
done
After you create it make it executable using chmod +x action.sh
After that you can start the script using nc 192.168.1.1 1012 | action.sh
And that's how you execute a script on an incomming call!
Special thanks to tgo!!
Related
I wrote a simple script that asks a user to edit the file until the moment when the user will enter the unused port. But it doesn't work (
while ! nc -z localhost $port; do
echo port is already used. Please choose another one.; read -p "Press enter to edit configuration file"; nano config.env;
done
$port it is an environment that the script takes from the current configuration file.
While loop doesn't start at all.
I have tried to run the script with ! and without ! the result is the same, looks like something wrong with the condition expression.
In order to test your scenario, I started an Apache httpd server on my laptop. It listens on port 80. Therefore nc -z localhost 80 will exit with status code 0.
This is my script:
#!/bin/bash
port=80
while nc -z localhost $port
do
echo "Port is already used. Please choose another one."
read -p "Press enter to edit configuration file or CTRL-C to terminate."
/usr/bin/nano config.env
wait
echo ""
done
To simplify, I set port to 80 statically in my script. Your version would read the port from config.env
When the user presses enter, the read completes, and the editor is called.
While the user edits the file, you want the script to wait. So until the editor is closed, the script does nothing. No point checking again for the port anyway.
When the editor is closed, wait is done and another loop starts.
I added "or CTRL-C to terminate" to give the user an out of the loop and the script.
For readability, you should put your commands on separate lines. Long series of commands on a single line, separated by ; can be confusing, and it serves no purpose. Carriage returns are not expensive :)
First, I would like to say that I know nothing about bash but I am trying to learn through practice.
So, I am trying to make a script which will send a magic packet to a remote host. While the remote host is starting I would like to print dots on the display.
I really don't have a problem with the wakeonlan part and of course I don't really need a script to do that. However, in order to learn something useful I try to make a script.
So my code is:
#!/bin/bash
! timeout 0.5 ping -c1 8.8.8.8 > /dev/null 2>&1
if [ $? -eq 1 ]
then
echo "Host is up"
else
wakeonlan FF:FF:FF:FF:FF:FF
echo "Host is starting ..."
while ! ping -c1 -w1 -n 8.8.8.8 > /dev/null 2&>1
do
printf "%c" "."
done
echo "Host is up!\n\n"
fi
exit 0
Now when the host is already up the while loop exits without printing. But when the host is down it outputs infinetely dots on the display, even if the host is up.
I really don't understand why the while loop does not stop when the condition is met.
I would appreciate your answer, especially if its aligned with my implementation.
Ok, I think I've figured out what's going on here. In the command
while ! ping -c1 -w1 -n 8.8.8.8 > /dev/null 2&>1
the & and > are in the wrong order. This causes a chain reaction of confusion and unexpected interpretations.
Specifically, bash parses 2&>1 as the argument "2" followed by the redirect &>1 which sents both stdout and stderr into a file named "1". So it runs this command, with all output to "1":
ping -c1 -w1 -n 8.8.8.8 2
Some versions of ping will give an error/usage message here, because they only accept a single target IP address (and then exit with an error status, making your loop run forever).
Other versions will interpret 8.8.8.8 as a hop to use on the way to the final destination 2, which is an old shorthand for the IP address 0.0.0.2. Which doesn't actually exist on the Internet. Which means the ping will fail and exit with an error status, making your loop run forever.
I suspect if you look in the file "1", you'll be able to tell which of these (or possibly something else) is happening.
There are some scripting lessons to be learned here:
All those cryptic piles of symbols matter, and if you get them a little bit wrong you can wind up doing something very different from what you intended.
Discarding output (especially error output) is a good way to hide what's going wrong. If a script is having trouble, capture & examine any errors its components produce.
set -x tells the shell to print what it thinks it's executing as it runs commands, and putting that before problem sections in scripts (and set +x afterward to turn it off) is a good say to find out what's going on. This is how I figured out that bash was treating "2" as an argument rather than part of the redirect.
shellcheck.net is handy!
for my work I need to connect to a lot of different servers every day: telnet ti the host, enter username, enter password - commence work.
Now I wanted to make life easier by automatically entering the username - I managed to do that, but telnet quits afterwards, that's obviously not what I wanted.
I work from a system with BASH and I can't install any programs there, so please don't give answers like "Use expect, that solves your problem easily..."
My tries led me to this:
function tn() { (echo "user"
sleep 1) | telnet $1 23
}
Calling the function with tn 123.45.67.89 connects to the server at 123.45.67.89, where the username is asked, which is entered automatically - great!
But then the password is asked, and instead of letting me enter it and begin my work, the connection is closed.
I really hope someone knows a solution for this!
Thanks in advance!
You might want to look at the expect command to script interactions with telnet:
#!/usr/bin/env bash
function tn() {
expect -f <<EOF
spawn telnet $1
expect "login"
send "${2}\r"
interact
EOF
}
telnetis designed for interactive usage. Use netcat, ncat, nc, socat or any other tool of this family.
Example:
( echo "user"; sleep 1) | ncat $1 23
But if you want to simulate interactive behavior, use socat and redirect stdin+stdout to a script:
Example:
socat TCP:$1:23 EXEC:my-shell.sh
In this case, a TCP connection for address $1 port 23 is established and stdin+stdout are redirected to stdout+stdin of the script. See man socat for details and more options.
my-shell.sh look for example like:
#!/bin/sh
read line
do_domething "$line"
printf "reply\n"
read line
do_domething "$line"
printf "reply\n"
btw, I have tested nothing (just written down)
I want to connect to a remote host using telnet
there is no username/password verification
just
telnet remotehost
then I need to input some commands for initialization
and then I need to repeat the following commands:
cmd argument
argument is read from a local file, in this file there are many lines, each line is a argument
and after runing one "cmd argument", the remote host will output some results
it may output a line with string "OK"
or output many lines, one of which is with string "ERROR"
and I need to do something according to the results.
basically, the script is like:
initialization_cmd #some initial comands
while read line
do
cmd $line
#here the remote host will output results, how can I put the results into a variable?
# here I want to judge the results, like
if $results contain "OK";then
echo $line >>good_result_log
else
echo $line >> bad_result_log
fi
done < local_file
the good_result_log and bad_result_log are local files
is it possible or not? thanks!
This won't work as echo will output to the stdout of the tty and not to the stdin of the telnet process.
I would suggest writing an expect script for this task. Perhaps you could adapt something like this.
This question was asked in at least four different forums at the same time. Don't know what kind of points this kind of entrepreneurship earns, but here are links to answers:
linux forums
unix.com
superuser.com
I use Ubuntu and am trying to write a script that makes the following:
-test if an audio stream works
-if not, send an email.
I have tried the following code (running as a cron job every 10 minutes), which 'works' if I supply the wrong pw e.g.(it sends an email then), but does nothing if the actual server is down (tested by killing the server). any ideas on how to fix the script?
Thanks in advance!
#!/bin/bash
#servertest.sh
username=user1
password=xyz
url="http://wwww.streamingaudioserver.com -passwd $password -user $username"
mplayer $url &
sleep 5
test=$(pgrep -c mplayer)
if [ $test = 0 ]; then
#server is down!
mailfile="downmail.txt"
/usr/sbin/ssmtp test#maildomain.com < "/home/test/$mailfile"
fi
killall mplayer
sleep 5
exit
Your problem is in this line:
$mailfile="downmail.txt"
remove the dollar sign and that should do it.
You should be getting error messages in your cron log or emails to the crontab owner complaining about a command not found or no such file.
Edit:
Does your script work if run from the command line (with the stream down) rather than cron?
Try using set -x (or #!/bin/bash -x) in the script to turn on tracing or use echo "PID: $$, value of \$test: $test" > /tmp/script.out after the assignment to see if you're getting the zero you're expecting.
Also, try an ssmtp command outside the if to make sure it's working (but I think you already said it is under some circumstances).
Try your script without ever starting mplayer.