In the first if we want the hostname to appear, which is the 5th field from a file. Then if the IP we give to the host command does not exist, then the command returns message 3 (NXDOMAIN). The script should recognize if the command was "not found". In this case it will
must simply print (-).
#!/bin/bash
ip="$1"
if [ "$ip" ] ; then
host "$ip" | cut -d' ' -f5
elif
[[ "$ip" =~ "[3(NXDOMAIN)]$" ]] ; then
echo "-"
fi
Do u have any solution on this exercise?
You're not testing the result of the host command, you're testing the value of the original $ip variable.
Save the output to a variable, test that variable, then either print the output or - depending on the test.
You don't need to do a regexp match, just match the exact string.
#!/bin/bash
ip="$1"
if [ "$ip" ] ; then
result=$(host "$ip" | cut -d" " -f5)
if [[ $result = "3(NXDOMAIN)" ]] ; then
echo "-"
else
echo "$result"
fi
fi
The answer is much simpler than you think, you don't need to do any matching. You can just use the return code from host
#!/bin/bash
ip="$1"
if domain=$(host "$1"); then
echo "${domain##* }"
else
echo "-"
fi
Proof of Concept
$ testHost(){ if domain=$(host "$1"); then echo "${domain##* }"; else echo "-"; fi }
$ testHost 172.217.6.46
sfo03s08-in-f14.1e100.net.
$ testHost 172.217.6.466
-
#!/bin/bash
if [ -n "$1" ] && [[ $1 =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$ ]] ;then
res=$(host "$1" | cut -d' ' -f5)
if [ "$res" != "3(NXDOMAIN)" ]; then
echo "$res"
else
echo "-"
fi
else
echo "please enter a valid ip"
fi
if you want to cover also ipv6 then I think this will cover it
#!/bin/bash
# ipv4
if [[ $1 =~ ^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])$ ]]; then
res=`host "$1" | cut -d' ' -f5`
if [ "$res" != "3(NXDOMAIN)" ]; then
echo "$res"
else
# valid ipv4 IP but not connected
echo "-"
fi
# ipv6
elif [[ $1 =~ ^(([[:xdigit:]]{1,4}:){7,7}[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}:){1,7}:|([[:xdigit:]]{1,4}:){1,6}:[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}:){1,5}(:[[:xdigit:]]{1,4}){1,2}|([[:xdigit:]]{1,4}:){1,4}(:[[:xdigit:]]{1,4}){1,3}|([[:xdigit:]]{1,4}:){1,3}(:[[:xdigit:]]{1,4}){1,4}|([[:xdigit:]]{1,4}:){1,2}(:[[:xdigit:]]{1,4}){1,5}|[[:xdigit:]]{1,4}:((:[[:xdigit:]]{1,4}){1,6})|:((:[[:xdigit:]]{1,4}){1,7}|:)|fe80:(:[[:xdigit:]]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])|([[:xdigit:]]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]]))$ ]]; then
res=`host "$1" | cut -d' ' -f5`
if [ "$res" != "3(NXDOMAIN)" ]; then
echo "1. $res"
else
# valid ipv6 IP but not connected
echo "2. -"
fi
else
echo "Please enter a valid IP"
fi
Note: For some versions of bash the -4 and -6 options do not work.
Thanks to Léa Gris for pointing out the locales problem.
Inspired from https://helloacm.com/how-to-valid-ipv6-addresses-using-bash-and-regex/
Related
So I'm making a shell script in Ubuntu. It's purpose is simple. You give a command with arguments and you get a different operation each time. The problem is that when I run the the script it won't actually run because of a syntax error in one elif. The most suspicious thing is that I have a similar elif above wich works or at least doesn't pop a syntax error...
I'm leaving my code for you to see it and understand. Thanks in advance!
if [ "$1" = "-a" -a $# -lt 3 ]
then
echo "Add a new line in katalogos!"
read -p "Give me a name... " name
read -p "Give me a surname... " surname
read -p "Give me a city name... " cityName
read -p "Give me a phone number... " num
echo "$name $surname $cityName $num" > katalogos
elif [ "$1" = "-l" -a $# -lt 3 ]
then
echo "Content of katalogos will be sorted numerically and blank lines will be excluded!"
sort -b -n katalogos
elif [ "$1" = "-s" -a $# -lt 4 ]
if [[ $2 != *[!0-9]* ]]
then
echo "Content of katalogos will be sorted according to the second argument!"
sort +$3 katalogos
fi
elif [ "$1" = "-c" -a $# -lt 4 ] // syntax error
if [[ $2 = *[!0-9]* ]]
then
echo "Content of katalogos will be sorted according to the keyword!"
if [ $(grep -e "$2" katalogos | wc -l) -eq 0 ]
then
echo "String is not matched."
else
grep -e "$2" katalogos
fi
fi
elif [ "$1" = "-d" -a ( "$3" = "-b" -o "$3" = "-r" ) ]
if [[ $2 = *[!0-9]* ]]
then
echo "Katalogos's string matching lines will be deleted and blank lines will be in their place, assuming that the third argument equals -b, else just the lines will be deleted!"
if [ $(grep -e $2 katalogos | wc -l) -eq 0 ]
then
echo "String is not matched."
else
if [ "$3" = "-b" ]
then
sed -i "$3" katalogos | sed -i '$ a '
echo "A blank line inserted in place of the deleted one."
else
sed -i "$3" katalogos
echo "Line deleted."
fi
fi
fi
elif [ "$1" = "-n" ]
echo "katalogos's number of blank lines will be shown with the ability to delete them!"
grep -cvP '\S' katalogos
read -p "Do you want to delete them? Type 1 for yes or 0 for no... " ans
if [ $ans -eq 1 ]
then
grep -cvP '\S' file | sed -i
echo "Lines deleted."
fi
else
echo "Help centre!"
echo "-Type ./telcat -a to insert a new line to katalogos."
echo "-Type ./telcat -l to see the contents of katalogos sorted numerically (excluding blank lines)."
echo "-Type ./telcat -s plus a number to see the contents of katalogos sorted by the data that the number points to."
echo "-Type ./telcat -c plus a keyword to see only the lines that match with the word given."
echo "-Type ./telcat -d plus a keyword and -b or -r to delete the lines that contain the word given. Specifically if the third argument is -b it will automatically add a blank line to the deleted one and if it is -r it will not."
echo "-Type ./telcat -n to see the number of blank lines of katalogos."
echo "End of help centre!"
fi
When I try to match a string and do some conditions; it always fails to do so.
date=`date +%Y%m%d`
kol="/home/user/test_$date"
regex='Terminating the script'
if [ -f $kol ]; then
sudo tail -f $kol | while read line; do
if [[ $line = *"Terminating the"* ]]
then
echo "failed"
else
echo $line >> /home/user/test123_$date
fi
else
echo "File is not yet present"
exit 0
fi
I have also tried with regex and that to failed. So when ever I input the matching string into the file ($path) it wont output "failed"; Is there anything wrong in the code. Help is much appreciated.
You can try this. At least it works for me:
sudo tail -f $1 | while read line; do
if [[ $line = '' ]]
then
break
fi
if [[ $line = *"Terminating the"* ]]
then
echo "failed"
else
echo $line >> /home/nurzhan/test123_$date
fi
done < "$1"
$path is parameter to the running script. Also note that by default the command tail returns only 10 last lines.
I've been playing with bash scripting for 40'ish days with 0 experience so forgive me if my code looks like crap. I have a script that will take the configured NTP servers out of the /etc/ntp.conf file (/root/ntp.conf for testing)
NTPSRVCounter=1
echo "--- NTP Configuration ---"
echo " "
while read -r line; do
if [ $NTPSRVCounter == 1 ] ; then
echo "Primary NTP: $line"
SEDConfiguredNTP1="$(echo $line | sed 's/\./\\./g')"
((NTPSRVCounter++))
echo " "
else
SEDConfiguredNTP2="$(echo $line | sed 's/\./\\./g')"
echo "Secondary NTP: $line"
echo ""
fi
done < <(grep -o -P '(?<=server ).*(?= iburst)' /root/ntp.conf)
And asks you if you want to change it with a case statement:
echo "Do you wish to change it? [Y/n]"
NTPSRVCounter2=1
read opt
case $opt in
Y|y) read -p "Enter in your primary NTP server: " -e -i '0.debian.pool.ntp.org' UserInputNTP1
read -p "Enter in your secondary NTP serer: " -e -i '1.debian.pool.ntp.org' UserInputNTP2
for NTP in "$UserInputNTP1" "$UserInputNTP2" ; do
is_fqdn "$NTP"
if [[ $? == 0 && $NTPSRVCounter2 == 1 ]] ; then
SEDUserInput1=$(echo $UserInputNTP1 | sed 's/\./\\./g')
((NTPSRVCounter2++))
elif [[ $? == 0 && $NTPSRVCounter2 == 2 ]] ; then
SEDUserInput2=$(echo $UserInputNTP2 | sed 's/\./\\./g')
sudo sed -i "s/$SEDConfiguredNTP1/$SEDUserInput1/g" /root/ntp.conf
sudo sed -i "s/$SEDConfiguredNTP2/$SEDUserInput2/g" /root/ntp.conf
else
echo "Fail!!! :-( "
fi
done
;;
N|n) return 0
;;
*) echo "I don't know what happened, but, eh, you're not supposed to be here."
;;
esac
The problem is with the "elif" statement and the function "is_fqdn" on the second run of the function. If I put "bash -x" on the script and run it, I see "is_fqdn" returning 0 on both runs of the function, but the elif statement "$?" is coming up as 1 instead of 0.
The two functions used are below. Have to validate NTP addresses as either valid domain names or I.P. addresses, right? :)
is_fqdn() {
hostname=$1
if [[ "$hostname" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
valid_ip "$hostname"
elif [[ "$hostname" == *"."* && "$hostname" != "localhost." && "$hostname" != "localhost" ]] ; then
return 0
else
return 1
fi
host $hostname > /dev/null 2>&1 || return 1
}
valid_ip(){
local stat=1
local ip=$1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
OIFS=$IFS
IFS="."
ip=($ip)
IFS=$OIFS
[[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
stat=$?
fi
return "$stat"
}
The condition in your if sets the value of $?, and that is what's used by the condition in the elif part, not the return value of is_fqdn. You need to save the value if you want to use it in multiple places:
is_fqdn "$NTP"
is_fqdn_rv=$?
if [[ $is_fqdn_rv == 0 && $NTPSRVCounter2 == 1 ]] ; then
SEDUserInput1=$(echo $UserInputNTP1 | sed 's/\./\\./g')
((NTPSRVCounter2++))
elif [[ $is_fqdn_rv == 0 && $NTPSRVCounter2 == 2 ]] ; then
SEDUserInput2=$(echo $UserInputNTP2 | sed 's/\./\\./g')
sudo sed -i "s/$SEDConfiguredNTP1/$SEDUserInput1/g" /root/ntp.conf
sudo sed -i "s/$SEDConfiguredNTP2/$SEDUserInput2/g" /root/ntp.conf
else
echo "Fail!!! :-( "
fi
I want to check if the input contains only alphanumeric characters and /slashes.
My code:
if [ ! -z `echo $2 | tr -d "[\/:alnum:]"` ]; then
echo "Error: input contains non-alphanumeric characters."
exit 1
fi
If I type .script.sh /example/test/ an error is thrown. Why?
You don't need tr, it can be done in pure BASH:
if [[ ! "$2" != *[^[:alnum:]/]* ]]; then
echo "Error: input contains non-alphanumeric characters."
exit 1
fi
EDIT: Thanks to #kojiro this solution won't need regex:
if [[ ! "$2" != *[^[:alnum:]/]* ]]; then
echo "Error: input contains non-alphanumeric characters."
exit 1
fi
You can use tr as tr -d '[:alnum:]\/'
Example:
str="123.abc?/123#"; tr -d '[:alnum:]\/' <<<$str
.?#
You can see in the example above anything that's not alphanumeric nor / gets printed.
Using within if:
str="abc123/"; if [ -n "$(tr -d '[:alnum:]\/' <<<$str)" ];then echo invalid; else echo valid; fi
valid
str="abc123/."; if [ -n "$(tr -d '[:alnum:]\/' <<<$str)" ];then echo invalid; else echo valid; fi
invalid
So Your code should look like:
if [ -n "$(tr -d '[:alnum:]\/' <<<$2)" ]; then
...
since it fails as long as you find a single [^0-9/] or $2 is EMPTY, you can probably take the following:
if [[ -z "$2" || "$2" =~ [^0-9/] ]]; then
echo "Error: input contains non-alphanumeric characters."
exit 1
fi
Here's the relevant parts of my bashrc:
function find_git_branch {
local dir=. head
until [ "$dir" -ef / ]; do
if [ -f "$dir/.git/HEAD" ]; then
head=$(< "$dir/.git/HEAD")
if [[ $head == ref:\ refs/heads/* ]]; then
git_branch=" (${head#*/*/})"
elif [[ $head != '' ]]; then
git_branch=' (detached)'
else
git_branch=' (unknown)'
fi
return
fi
dir="../$dir"
done
git_branch=''
}
function shortpath {
# How many characters of the $PWD should be kept
local pwd_length=40
local lpwd="${PWD/#$HOME/~}"
if [ $(echo -n $lpwd | wc -c | tr -d " ") -gt $pwd_length ]
then newPWD="...$(echo -n $lpwd | sed -e "s/.*\(.\{$pwd_length\}\)/\1/")"
else newPWD="$(echo -n $lpwd)"
fi
echo $newPWD
}
PROMPT_COMMAND="find_git_branch; $PROMPT_COMMAND"
# PS1 prompt color vars
CYAN="\e[36m"
RED="\e[31m"
GREEN="\e[32m"
DEFAULT="\e[0m"
TIME="[\t]"
DIRNAME="\w"
export PS1="\u#\h:\[$CYAN\]\$(shortpath)\[$GREEN\]\[\$git_branch\]\[$DEFAULT\] \$ "
It works well, but sometimes as I type or hit the up arrow for previous commands, part of the prompt gets overwritten in the terminal. Why does this happen?
Looks like you're including your $git_branch part in a non-printing-chars block (\[...\]).