How to get IP of a domain requested with wget? - shell

I'm searching for a way to fetch IP address of the domain requested with wget command, when the command fails.
I can't use ping command for fetching the IP, because the address may change after the wget command is terminated.
I would like to perform this in a shell script.

When wget fails, it terminates with non-zero exit status, and the errors are written to the standard error descriptor (2).
So you can check the exit code ($? variable), and parse the strings written to the standard error:
url='http://stackoverflow.com/users/edit/1646322'
output=$( wget "$url" 2>&1 )
if [[ $? -ne 0 ]]; then
printf '%s' "$output" | \
perl -ne '/^Connecting to .*\|([^\|]+)\|/ and print $1'
fi
Sample Output
151.101.129.69

Related

BASH If command contains 'this text' do another command?

I'm creating a bash script to check the HTTP headers on remote hosts, I'm doing this via cURL and have noted that appending http://{host} will only work for services running on tcp\80, and not tcp\443. For example for HTTPS services, you require curl -I -k {host}, as opposed to HTTP services which only required curl -I {host}. This is my script:
for host in $(cat file.txt); do
echo " "
echo "Current host: "${host}
curl -I -k https://${host}
echo " "
echo "=============================================="
done
Now what I'm wanting is some condition operator to check that if the output is "Could not resolve host" then the script should run "curl -I http://{host}" on those hosts which the stdout contained the str value "Could not resolve host".
How can I achieve this in bash?
stdout will not contain Could not resolve host though, that's output to stderr. While you could capture stderr and then do string matching, there is a much, much simpler solution: exit code.
You can see here that curl will always exit with code 6 when it fails to resolve host. Thus, simply testing the exit code is sufficient:
curl -i -k http://nowaythisthingexists.test
if [[ $? -eq 6 ]]
then
echo "oopsie, couldn't resolve host!"
fi
Alternately, if you really want to do it by matching strings, make sure to redirect stderr to stdout (and possibly also kill stdout so it doesn't interfere):
output=$(curl -i -k http://nowaythisthingexists.test 2>&1 >/dev/null)
if [[ "$output" = *"Could not resolve host"* ]]
then
echo "oopsie, couldn't resolve host!"
fi
Obviously, you are not getting the output of your request this way, so you'd need to redirect it somewhere more useful than /dev/null — a file, or a Unix pipe. Now it's getting more complicated than it needs to be.

How to get exit codes for different sections of a command in bash

Let's say I have a line in my bash script with ssh bad#location "find -name 'fruit.txt' | grep "Apple" and I'm trying to retrieve the exit codes of ssh, find . -name 'fruit.txt', and "grep "Apple` to see which command went bad.
So far, I've tried something like echo $? ${PIPESTATUS[0]} ${PIPESTATUS[1]}, but it looks like $? returns the same thing as ${PIPESTATUS[0]} in this case. I only need to return the first non-zero exit code along with dmesg for debugging purposes.
I've also considered using set -o pipefail, which will return a failure exit code if any command errors, but I'd like to somehow know which command failed for debugging.
I'd like either get an exit code of 255 (from ssh) and its corresponding dmesg, or somehow get all of the exit codes.
ssh only returns one exit status (per channel) to the calling shell; if you want to get exit status for the individual pipeline components it ran remotely, you need to collect them remotely, put them in with the data, and then parse them back out. One way to do that, if you have a very new version of bash, is like so:
#!/usr/bin/env bash
# note <<'EOF' not just <<EOF; with the former, the local shell does not munge
# heredoc contents.
remote_script=$(cat <<'EOF'
tempfile=$(mktemp "${TMPDIR:-/tmp}/output.XXXXXX"); mktemp_rc=$?
find -name 'fruit.txt' | grep Apple >"$tempfile"
printf '%s\0' "$mktemp_rc" "${PIPESTATUS[#]}"
cat "$tempfile"
rm -f -- "$tempfile"
exit 0 # so a bad exit status will be from ssh itself
EOF
)
# note that collecting a process substitution PID needs bash 4.4!
exec {ssh_fd}< <(ssh bad#location "$remote_script" </dev/null); ssh_pid=$!
IFS= read -r -d '' mktemp_rc <&$ssh_fd # read $? of mktemp
IFS= read -r -d '' find_rc <&$ssh_fd # read $? of find
IFS= read -r -d '' grep_rc <&$ssh_fd # read $? of grep
cat <&$ssh_fd # spool output of grep to our own output
wait "$ssh_pid"; ssh_rc=$? # let ssh finish and read its $?
echo "mktemp exited with status $mktemp_rc" >&2
echo "find exited with status $find_rc" >&2
echo "grep exited with status $grep_rc" >&2
echo "ssh exited with status $ssh_rc" >&2
How does this work?
exec {fd_var_name}< <(...) uses the bash 4.1 automatic file descriptor allocation feature to generate a file descriptor number, and associate it with content read from the process substitution running ....
In bash 4.4 or newer, process substitutions also set $!, so their PIDs can be captured, to later wait for them and collect their exit status; this is what we're storing in ssh_pid.
IFS= read -r -d '' varname reads from stdin up to the next NUL (in read -d '', the first character of '' is treated as the end of input; as an empty string in a C-derived language, the first byte of the string is its NUL terminator).
This could theoretically be made easier by writing the output before the exit status values -- you wouldn't need a temporary file on the remote machine that way -- but the caveat there is that if there were a NUL anywhere in the find | grep output, then some of that output could be picked up by the reads. (Similarly, you could store output in a variable instead of a temporary file, but again, that would destroy any NULs in the stream's output).

Bash script command and getting rid of shellcheck error SC2181

I have the following bash script:
dpkg-query --show --showformat='${Status}\n' "$i" 2> \
/dev/null | grep "install ok installed" &> /dev/null
if [[ $? -eq 0 ]]; then
l_var_is_desktop="true"
fi
and the ShellCheck utility (https://www.shellcheck.net/) is giving me the following output:
$ shellcheck myscript
Line 17:
if [[ $? -eq 0 ]]; then
^-- SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.
$
The link to this warning is the following: https://github.com/koalaman/shellcheck/wiki/SC2181
What is the best way for modifying this. The command is really too long to put into one line. I would like to avoid using ShellCheck ignore rules.
I've tried creating a local variable and storing the output of the command, but this breaks other rules.
The command doesn't really get much longer by putting it directly in if, you're just adding 3 characters.
if dpkg-query --show --showformat='${Status}\n' "$i" 2> \
/dev/null | grep "install ok installed" &> /dev/null
then
l_var_is_desktop="true"
fi

egrep is returning 0 in bash script but executing manually the command returning correct value | unix bash

I'm executing a bash script that returns me if ftp connection failed or was success using egrep, the issue is that when I'm trying to get a word with egrep is returning 0 but If I execute the command manually is returning 2.
this is my code:
#Create the FTP Connection.
for ip_address in ${IP_ADDRESS[#]}; do
ftp ${ip_address} <<ftp_commands > ${FTP_RESULTS}
user "${USER_ID}" "${USER_PASSWORD}"
pwd
bye
ftp_commands
ftp_result_id=`egrep -c "Login failed|Connection refused|Not connected|Connection timed out" ${FTP_RESULTS}`
if [ ${ftp_result_id} -gt 0 ]; then
echo "$(date +%m/%d/%y_%H:%M:%S) - ${ip_address} - Not connected" >> ${CONNECTION_RESULTS_FILE}
else
echo "$(date +%m/%d/%y_%H:%M:%S) - ${ip_address} - Connected" >> ${CONNECTION_RESULTS_FILE}
fi
done
the ftp_results_id is returning 0 in the egrep -c command, but I'm executing manually after it ran and create the file "FTP_RESULTS" and is working, it suppose that found 2 matches with "Not connected"
any suggestion?
The egrep -c command counts the matches.
Then you use a condition to do something if there are more than 0 matches.
A simpler and better solution is to use the exit code of egrep.
egrep exits with 0 (= success) if it found a match,
and non-zero otherwise.
You can write the if statement like this:
if egrep -q "Login failed|Connection refused|Not connected|Connection timed out" "${FTP_RESULTS}"; then
This is equivalent to the logic in your posted code.
There's no need for the ftp_result_id variable.
And there's no need to save the output of egrep.
I added the -q flag so that egrep doesn't produce any output.
None needed.

the bash script only reboot the router without echoing whether it is up or down

#!/bin/bash
ip route add 10.105.8.100 via 192.168.1.100
date
cat /home/xxx/Documents/list.txt | while read output
do
ping="ping -c 3 -w 3 -q 'output'"
if $ping | grep -E "min/avg/max/mdev" > /dev/null; then
echo 'connection is ok'
else
echo "router $output is down"
then
cat /home/xxx/Documents/roots.txt | while read outputs
do
cd /home/xxx/Documents/routers
php rebootRouter.php "outputs" admin admin
done
fi
done
The other documents are:
lists.txt
10.105.8.100
roots.txt
192.168.1.100
when i run the script, the result is a reboot of the router am trying to ping. It doesn't ping.
Is there a problem with the bash script.??
If your files only contain a single line, there's no need for the while-loop, just use read:
read -r router_addr < /home/xxx/Documents/list.txt
# the grep is unnecessary, the return-code of the ping will be non-zero if the host is down
if ping -c 3 -w 3 -q "$router_addr" &> /dev/null; then
echo "connection to $router_addr is ok"
else
echo "router $router_addr is down"
read -r outputs < /home/xxx/Documents/roots.txt
cd /home/xxx/Documents/routers
php rebootRouter.php "$outputs" admin admin
fi
If your files contain multiple lines, you should redirect the file from the right-side of the while-loop:
while read -r output; do
...
done < /foo/bar/baz
Also make sure your files contain a newline at the end, or use the following pattern in your while-loops:
while read -r output || [[ -n $output ]]; do
...
done < /foo/bar/baz
where || [[ -n $output ]] is true even if the file doesn't end in a newline.
Note that the way you're checking for your routers status is somewhat brittle as even a single missed ping will force it to reboot (for example the checking computer returns from a sleep-state just as the script is running, the ping fails as the network is still down but the admin script succeeds as the network just comes up at that time).

Resources