Regex to match IP addresses but ignore localhost - linux

So I have this script that does something with IPs allocated to my OS (GNU/Linux) that I get from running ifconfig. It works fine, however, I was wondering if I could filter out loopback/localhost IP (127.0.0.1) in the same regex expression [I assume every server within my cluster has said IP and I don't need to do anything with it in my script.]
What my script uses is:
ifconfig | awk '/(([0-9]{1,3}\.){3})/ {print}' |sed -e "s/.*addr\://g" -e "s/\s.*//g"
I get results like:
> ifconfig | awk '/(([0-9]{1,3}\.){3})/ {print}' |sed -e "s/.*addr\://g" -e "s/\s.*//g"
172.16.0.1
127.0.0.1
I know it might be a stupid question, but could I filter any IP that starts with 127 in my first regex?
I could try changing awk for grep, somethin like:
> ifconfig |egrep -o "addr\:(([0-9]{1,3}\.){3}[0-9]{1,3})" |sed -e "s/.*addr\://g"
but if I try to negate (?!127) at the beginning, bash will interpret it as !127 which would just throw me something from the history.
I mean, I could just run another grep at the end of the oneliner like grep -v "127.0.0.1", but I just wanted to avoid greping something already greped. Not that anything is wrong with that, just trying to know little more and be more efficient, I guess.

With only one grep without sed or awk:
# ip a|grep -oP "inet \K[0-9.]*(?=.*[^ ][^l][^o]$)"
192.168.1.31
172.16.5.31

You can just add a clause to match the 127.0.0.1 and exclude it by adding the next as below. This way Awk ignores doing any action on the lines containing this pattern.
.. | awk '/127.0.0.1/{next}/(([0-9]{1,3}\.){3})/{print}' | ..

Related

Calling a command variable on Bash [duplicate]

This question already has answers here:
Command not found error in Bash variable assignment
(5 answers)
Closed 4 years ago.
Im having trouble calling a variable that should bring out the output of a command.
#!/bin/bash
ipAddresses = 'ifconfig | awk -v OFS=": " -v RS= '$1!="lo" && split($0, a, /inet addr:/) > 1{sub(/ .*/, "", a[2]); print $1, a[2]}''
echo -e "Sus direcciones IP son: \n " $(ipAddresses)
Appreciating any advice
Variable assignments cannot have space around the = in the shell. Also, you don't want single quotes there, you want either backticks or $(). The single quotes should only be for your awk command. Your awk is needlessly complicated as well, and you are using command substitution ($()) when printing, but ipAdresses is a variable, not a command.
Try something like this:
#!/bin/bash
ipAddresses=$(ifconfig | sed 's/^ *//' | awk -F'[: ]' '/^ *inet addr:/{print $3}')
printf 'Sus direcciones IP son:\n%s\n' "$ipAddresses"
But that is really not portable. You didn't mention your OS, but I am assuming it's a Linux and the output suggests Ubuntu (I don't have addr after inet in the output of ifconfig on my Arch, for example).
If you are running Linux, you could use grep instead:
ipAddresses=$(ifconfig | grep -oP 'inet addr:\K\S+')
ip is generally replacing ifconfig, so try this instead:
ipAddresses=$(ip addr | awk '/inet /{print $2}')
or
ipAddresses=$(ip addr | grep -oP 'inet \K\S+')
Or, to remove the trailing /N:
ipAddresses=$(ip addr | grep -oP 'inet \K[\d.]+')
And you don't need the variable anyway, you can just:
printf 'Sus direcciones IP son:\n%s\n' "$(ip addr | awk '/inet /{print $2}')"
I am not sure about your intention, since they are not stated, so I am trying to guess them from the script.
Option 1: you are trying to get IP address to into the variable ipAddresses and that is not happenning.
Start by changing single quotes around the long command and debug the command.
Option 2: you are storing a command in variable ipAddresses that you want to execute on the second line.
For both of the options you need to use the the value of the variable through $ipAdresses on the second line.
Also fix the assignment to following formart:
varName="value" # Note no spaces around = sign
Replace the final $(ipAddresses) with ${ipAddresses} or just "$ipAddresses", but also save the output of your command using $().
Check Difference between ${} and $() in Bash.
A basic example:
#!/bin/sh
OUTPUT=$(uname -a)
echo "The output: $OUTPUT"

Print a certain line in linux or options for nslookup

I'm very new to linux and bash. I'm trying to find a domain name for an ip address. When I use nslookup I have a bunch of lines like this
nslookup 204.228.150.3
Output
Server: 198.60.22.2
Address: 198.60.22.2#53
Non-authoritative answer:
3.150.228.204.in-addr.arpa name = www.computerhope.com.
Authoritative answers can be found from:
150.228.204.in-addr.arpa nameserver = ns.xmission.com.
150.228.204.in-addr.arpa nameserver = ns1.xmission.com.
150.228.204.in-addr.arpa nameserver = ns2.xmission.com.
ns.xmission.com Internet address = 166.70.254.2
ns1.xmission.com Internet address = 204.228.159.2
ns2.xmission.com Internet address = 207.135.133.2
I only want to print www.computerhope.com in the second line. How do I do this?
Also I tried to use host command as well. It looks cleaner.
206.153.126.75.in-addr.arpa domain name pointer www.cyberciti.biz.
How do I only print www.cyberciti.biz when I use host command ?
PLease help
$ host 75.126.153.202 |sed -e 's/.* //'
www.cyberciti.biz.
nslookup 204.228.150.3 | \
grep "in-addr.arpa" | \
cut -d '=' -f 2 | \
tr -d '[:blank:]'
With grep you find the line containing the address. With the cut command you split the line by the "=" sign. With tr you remove any remaining spaces.
The command does not have any error handling in case the address is unknown.
If you would provide more information on what you want to achieve maybe other solutions would come up. :-)
Another way to do this is to pipe the host command to awk:
$ host 75.126.153.202 | awk '{print $NF}'
NF is a built-in awk variable which prints the last column of the output of the host command, which in this case is the domain name.
You can also pipe nslookup to awk:
$ nslookup 75.126.153.202 | awk '$2 ~ /^name$/{print $NF}'
awk returns the last column of the line containing the name in its 2nd column.

How do I wrtite the current IP of tun0 into a txt file with a shell script?

#!/bin/sh
/sbin/ifconfig tun0 | grep 'inet addr:' | cut -d: -f2 | awk '{print $1}' > ./tun0_ip.txt
This works very good when I put it into the command line.
However it does not work with a sh script.
What am I doing wrong?
Why do some commands not work with a sh script?
~$ bash -x ./reset.sh
+ echo /sbin/ifconfig tun0
+ grep 'inet addr:'
+ cut -d: -f2
+ awk '{print $1}'
It is strange that you are testing with bash, while giving #!/bin/sh as shebang line.
However this is probably not the reason this does not work. Definitely, whether you run some commands from the command line or from a script with the exact same environment, they should not give you a different result.
Maybe the user that calls the script has a different locale, so the output of ifconfig is no more 'inet addr' but something else? Or some environment variable that changes the form of ifconfigs output is not exported?
You can find out only, by going step by step. Looking at the script it should be some problem with ifconfig not giving you, what you expect. So simply take a look at the output of that from the script, unchanged.

how to match hostname machine

please advice how to match the following hostname
machine hostname Should be according to the following rule
<a-z word ><number><a-z character/s>
real example
star1a
linux25as
machine2b
linux5a
solaris300C
unix9c
please advice how to machine these hostname with grep
I have for now this syntax
hostname | grep -c '[a-z][1-2][a-z]'
but these syntax not work on all my examples
on solaris the option egrep -E not works
hostname | grep -E '\b[a-z]+[0-9][a-z]+'
grep: illegal option -- E
Usage: grep -hblcnsviw pattern file . . .
Broken Pipe
try the second option ( on solaris machine ):
hostname
swu2a
hostname | grep "^[a-z]\+[0-9][a-z]\+$"
not matched!!!
I also try this:
hostname
swu2a
hostname | grep '[a-z]\+[0-9]\+[a-zA-Z]\+'
NOT MATCHED!!!
Here is an awk using same regex as the grep posted here uses.
awk '/[a-z]+[0-9]+[a-zA-Z]+/'
star1a
linux25as
machine2b
linux5a
solaris300C
unix9c
If you need to make sure there is nothing else in the line, only the words above, use:
awk '/^[a-z]+[0-9]+[a-zA-Z]+$/'
^ marks start of line.
$ marks end of line.
You can use the following pattern:
grep '^[a-z]\+[0-9]\+[a-zA-Z]\+$'
Note that you can use the the return value of grep to decide whether the pattern matches or not, you don't need to use the -c option. Like this:
if [ hostname | grep '^[a-z]\+[0-9]\+[a-zA-Z]\+$' >/dev/null 2>&1 ] ; then
echo "host name OK"
fi

How to find network interface name

I have a bash script that runs on a variety of different Ubuntu Linux machines. Its job is to find out the LAN IPv4 address of the localhost.
The script is using
ip addr show eth0 | sed -n '/inet /{s/^.*inet \([0-9.]\+\).*$/\1/;p}'
which is fine, but some machines for some reason use eth1 instead of eth0. I would like to be able to discover the LAN iface name, so I can substitute it in here instead of eth0.
Of course, if you can come up with a different oneliner that does the same thing, all good.
The main NIC will usually have a default route. So:
ip -o -4 route show to default
The NIC:
ip -o -4 route show to default | awk '{print $5}'
The gateway:
ip -o -4 route show to default | awk '{print $3}'
Unlike ifconfig, ip has a consistent & parsable output. It only works on Linux; it won't work on other Unixen.
Not sure if this helps, but it seems that ip route get will show which interface it uses to connect to a remote host.
ubuntu#ip-10-40-24-21:/nail/srv/elasticsearch$ ip route get 8.8.8.8
8.8.8.8 via <gateway address> dev eth0 src <eth0 IP Address>
of course you could automate that in shell script with something like,
ip route get 8.8.8.8 | awk '{ print $NF; exit }'
Most recenttly systemd/udev has automatically started to assign interface names for all local Ethernet, WLAN and WWAN interfaces to something that we're all accustomed to . This is a departure from the traditional interface naming scheme ("eth0", "eth1", "wlan0", ...) .. now we have to check first what the local interface name is before we can use it while previously we it was a pretty accurate guess that "eth0" was the right name. What you're asking for is the network NAME .. Here's a small script to solve the problem
Use "ip route get 8.8.8.8 " to figure out which ACTIVE interface has the route to internet ( or currently being used )
Output should look like :
8.8.4.4 via 10.10.1.1 dev enp0s3 src 10.10.1.118
cache
Use awk to print the 5th text block for Interface NAME
]# ip route get 8.8.8.8 | awk -- '{print $5}'
Output : enp0s3
Use awk to print the 7th text block for Interface Address
]# ip route get 8.8.8.8 | awk -- '{print $7}'
Output : 10.10.1.118
How about searching for the string inet and brd (for broadcast)? That would give you:
ip addr show|egrep '^ *inet'|grep brd|awk -- '{ print $2; }'|sed -e 's:/[0-9]*$::'
Note that I'm using more commands than necessary; you can probably achieve the same thing with sed and a more complex regexp but I prefer a command that makes it obvious by which steps I arrive at the result.
If you want to run it in a single command, I suggest to try awk:
ip addr show|awk -- '$1 == "inet" && $3 == "brd" { split($2,a,"/"); print a[1]; }'
which isn't much longer than the sed version but more readable.
+1 Slightly more readable:
ip addr show | awk '$1 == "inet" && $3 == "brd" { sub (/\/.*/,""); print $2 }'
Believe it or not, there is no standard, easy way to get this information. There is no standard give me the current IP and Interface Name command. There isn't even a standard format for the information returned by ifconfig.
I was going to recommend forgoing pure shell and go with a scripting language like Python where you can do this:
import socket
socket.gethostbyname(socket.gethostname())
Except it doesn't work on most Linux systems because there's usually an entry in the /etc/host file pointing to 127.0.0.1, the loopback address. Perl has the same issues.
You have a firm grasp on the scripting involved, and you've seen the issues. The only thing I can recommend is to test this on each machine you're going to run it on, and see what pops out. There isn't going to be a general purpose one liner that works with all operating systems, or even with different systems on the same operating system because of the way the network is setup and the way interfaces may be named by each location.
I'd still like to know if there was an easier way to do this, but this is my workaround: I know the LAN subnet, so...
ip addr show | grep "inet 10.67.5." \
| sed -n '/inet /{s/^.*inet \([0-9.]\+\).*$/\1/;p}'
1) This one print only interface names (I needed that for handing upcoming and downcoming PPP links):
for i in $( ifconfig | grep 'ppp' | awk '{print $1}' );
do
printf "$i "; ## Or echo
done
Result:
ppp0 ppp1 ppp2
2) This one prints interface names and IP
declare -a IPADDR
index=0
for i in $( ifconfig | grep 'inet addr' | awk '{print $2}'| sed 's#addr:##g' );
do
IPADDR[$index]=$i
let "index += 1"
done
index=0
for i in $( ifconfig | grep 'ppp' | awk '{print $1}' );
do
echo $i
let "index += 1"
done
Result:
ppp0 addr:IP
ppp1 addr:IP
ppp2 addr:IP

Resources