I'm trying to automate telnet, using this command which works great
echo -e "\x1dclose\x0d" |
telnet abc.gc.ca 100 |
grep Connected>/dev/null && printf "PASSED\n" || printf "FAILED\n"
But if I put it in a script, it just hangs and I have no idea why.
#!/bin/bash
SERVERS=(
"abc.gc.ca 100"
"defg.gc.ca 101"
"123.gc.ca 102"
"xyz.gc.ca 103"
)
for host in ${SERVERS[@]}; do
echo -e "\x1dclose\x0d" |
telnet $host |
grep Connected > /dev/null && printf "PASSED\n" || printf "FAILED\n"
done
The big problem was with the array dereference: Using ${SERVERS[@]}
without quotes around it was treating the port as a separate hostname.
#!/bin/bash
servers=(
abc.gc.ca:100
defg.gc.ca:101
123.gc.ca:102
xyz.gc.ca:103
)
for host_port in "${servers[@]}"; do
host=${host_port%:*} # put everything before the last : into host
port=${host_port##*:} # put everything after the last : into port
if printf '\x1dclose\x0d' | telnet "$host" "$port" | grep -q Connected; then
printf "PASSED\n"
else
printf "FAILED\n"
fi
done
Other notes:
foo && bar || baz
is not identical to if foo; then bar; else baz; fi
. For reliable code, use if
-- not a short-circuiting ternary -- when you want the behavior of if
.grep -q
causes grep
not to emit any output, so you don't need to redirect that output.echo -e
is not reliable: even if the shell is 100% certain to be bash, if the shell is compiled or configured at runtime to provide an XPG-compatible echo
(configuration that can be done through environment variables), echo -e
may print -e
on output instead of treating it as an argument.All that said, consider using a dedicated port-scanning tool if this is intended for any kind of real-world use case. Such tools (nmap &c) can scan a large number of hosts in parallel without needing to run a subprocess for each, much less several subprocesses as used here.