Bash script issue - bash

I can run this command fine, with the output I want:
ifconfig eth0 | grep HWaddr | awk '{print $5}'
However, when I set the command to a variable, and print the variable, I get an error:
CASS_INTERNAL=`ifconfig eth0 | grep HWaddr | awk '{print \$5}'`
$CASS_INTERNAL
my internal xxx ip: command not found
The weird thing - my internal IP actually shows up. How do I go about this without getting an error? It shouldn't matter, but I'm using the latest version of Ubuntu.

You're not printing the variable, you're running it as a command name. You're looking for
echo "$CASS_INTERNAL"
(Get into the habit of always putting double quotes around variable substitutions.)
More advanced shell note: in this case it doesn't matter, but in general echo can have trouble with some special characters (- and \\), so it's better to use the following more complicated but fully reliable command:
printf "%s\n" "$CASS_INTERNAL"

don't have to use grep
ifconfig eth0 | awk '/HWaddr/{print $5}'

CASS_INTERNAL=`ifconfig eth0 | grep HWaddr | awk '{print \$5}'`
echo $CASS_INTERNAL
Your:
$CASS_INTERNAL
Would try to run it as a command.

do you maybe want
echo $CASS_INTERNAL

Well, you grep for HWaddr first, so the fifth field on this this line is the MAC address of the network adapter in question - not your local IP address.
Others have suggested the solution is to simply echo the result, meaning if eth0 in this example is not available at that point in time which the line gets executed, it will not work.
From what I understand you wish instead to put the desired command line in a variable, then evaluate it later on. This pattern is commonly called lazy evaluation, and is made possible in bash by using the eval builtin:
#put the desired command in variable
CASS_INTERNAL='ifconfig eth0 | grep HWaddr | awk "{print \$5}"'
# ....
#at later on - evaluate its contents!
eval $CASS_INTERNAL
11:22:33:aa:bb:cc

Related

grep exact string by pattern in variable

I want to grep exact string by pattern in variable
ip="192.168.100.1"
arp -a | grep "$ip"
This outputs something like this:
# arp -a | grep "$ip"
? (192.168.10.1) at 66:ca:6d:88:57:cd [ether] on br0
? (192.168.10.15) at 3c:15:a0:05:b5:94 [ether] on br0
but I want exactly IP no IP of other PCs
Also I have only embedded grep (minimalistic) also I have awk,sed.
Im trying this but without success:
arp -a | grep "\b$ip\b"
Word boundaries like \b aren't available with standard grep. From the output snippet you posted it looks like this will work for you:
$ ip="192.168.10.1"
$ grep -F "($ip)" file
? (192.168.10.1) at 66:ca:6d:88:57:cd [ether] on br0
i.e. just use -F for a string instead of regexp comparison and explicitly include the delimiters that appear around the IP address in the input.
FWIW in awk it'd be:
$ awk -v ip="($ip)" 'index($0,ip)' file
? (192.168.10.1) at 66:ca:6d:88:57:cd [ether] on br0
and you can't do it in a reasonable way in sed since sed ONLY supports regexp comparisons, not strings (see Is it possible to escape regex metacharacters reliably with sed).
If I understand correctly what you are saying you just want to add a -o option to your command, the -o option print only the matched (non-empty) parts of a matching line,with each such part on a separate output line.
arp -a | grep -o "$ip"

"sed/awk" value assignment in bash scripting

I have a file "IP" with number of blocked different subnet IP addresses, I want to change last octal digits of subnet, like 1.1.1.5 to 1.1.1.0/24. I wrote script. Issue is that awk command out doesn't assigned to any variable.
Example:
sed "s/139.196.8.79/139.196.8.0\/24/g" ip |a=$(awk -F. '{print $4}')
But when I run awk -F. '{print S4}', it returns output but doesn't assign value to variable.
Thanks in advance.
Not sure about your expected output but... looking your example here above, maybe, you're looking for something like this:
$ a=$(sed "s/139.196.8.79/139.196.8.0\/24/g" ip | awk -F. '{print $4}')
$ echo $a
0/24
WHat you were trying to write is:
a="$(sed "s/139.196.8.79/139.196.8.0\/24/g" ip | awk -F. '{print $4}' )"
but you need to escape the RE metacharacters (.s) and you don't need sed when you're using awk:
a="$(awk -F. '{gsub(/139\.196\.8\.79/,"139.196.8.0/24"); print $4}' ip)"
The above is untested and may be wrong or not the best approach since you didn't provide any sample input and expected output in your question.
Note that the above should really be using word boundaries if an IP addr like 139.196.8.790 can occur in your data but again without sample input and expected output....
A pipe creates a sub process. This means that you create the variable in a sub shell, which gets discarded right after. In order to access the variable, you have to group your commands into curly braces:
sed "s/139.196.8.79/139.196.8.0\/24/g" ip | {
a=$(awk -F. '{print $4}')
echo $a
}
Everything you want to do with a must be done in the sub shell, in which a has been defined.

How to get ip address of a server on Centos 7 in bash

Previously I used the following command in bash to find the main ip of my server
ipaddr=$(/sbin/ifconfig|grep inet|head -1|sed 's/\:/ /'|awk '{print $3}' | grep -v '127.0.0.1')
But in centos7 it no longer works since ifconfig isn't available and the command no longer works even if I install ifconfig using yum install net-tools
What is the equivalent command for centos 7
Thanks a lot
You can use hostname command :
ipaddr=$(hostname -I)
-i, --ip-address:
Display the IP address(es) of the host. Note that this works only if the host name can be resolved.
-I, --all-ip-addresses:
Display all network addresses of the host. This option enumerates all configured addresses on all network interfaces. The loopback interface and IPv6 link-local addresses are omitted. Contrary to option -i, this option does not depend on name resolution. Do not make any assumptions about the order of the output.
Ref: https://garbagevalue.com/blog/4-simle-ways-to-check-ip-adress-in-centos-7
I'm using CentOS 7 and command
ip a
is enough to do the job.
Edit
Just slice out the IP address part from that test.
ip a | grep 192
Enter the command ip addr at the console
hostname -I | awk ' {print $1}'
Something like this - a riff on #maarten-vanlinthout's answer
ip -f inet a show eth0| grep inet| awk '{ print $2}' | cut -d/ -f1
SERVER_IP="$(ip addr show ens160 | grep 'inet ' | cut -f2 | awk '{ print $2}')"
replace ens160 with your interface name
You can run simple commands like
curl ifconfig.co
curl ifconfig.me
wget -qO - icanhazip.com
Actually, when you do not want to use external sources (or cannot), I would recommend:
DEVICE=$(ls -l /sys/class/net | awk '$NF~/pci0/ { print $(NF-2); exit }')
IPADDR=$(ip -br address show dev $DEVICE | awk '{print substr($3,1,index($3,"/")-1);}')
The first line gets the name of the first network device on the PCI bus, the second one gives you its IP address.
BTW ps ... | grep ... | awk ...
stinks. awk does not need grep.
Bit late however I use
curl -4 icanhazip.com
returns the server Primary IP address.
I believe that the most reliable way to get the external server ip address would be to use an external service.
ipaddr=$(curl -s http://whatismyip.akamai.com/)
Run this command to show ip4 and ip6:
ifconfig eth0 | grep inet | awk '{print $2}' | cut -d/ -f1

Putting IP Address into bash variable. Is there a better way

I'm trying to find a short and robust way to put my IP address into a bash variable and was curious if there was an easier way to do this. This is how I am currently doing it:
ip=`ifconfig|xargs|awk '{print $7}'|sed -e 's/[a-z]*:/''/'`
I've been struggling with this too until I've found there's a simple command for that purpose
hostname -i
Is that simple!
man hostname recommends using the --all-ip-addresses flag (shorthand -I ), instead of -i, because -i works only if the host name can be resolved. So here it is:
hostname -I
And if you are interested only in the primary one, cut it:
hostname -I | cut -f1 -d' '
ip is the right tool to use as ifconfig has been deprecated for some time now. Here's an awk/sed/grep-free command that's significantly faster than any of the others posted here!:
ip=$(ip -f inet -o addr show eth0|cut -d\ -f 7 | cut -d/ -f 1)
(yes that is an escaped space after the first -d)
You can take a look at this site for alternatives.
One way would be:
ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'
A bit smaller one, although it is not at all robust, and can return the wrong value depending on your system:
$ /sbin/ifconfig | sed -n '2 p' | awk '{print $3}'
(from http://www.htmlstaff.org/ver.php?id=22346)
The ifdata command (found in the moreutils package) provides an interface to easily retrieve ifconfig data without needing to parse the output from ifconfig manually. It's achieved with a single command:
ifdata -pa eth1
Where eth1 is the name of your network interface.
I don't know how this package behaves when ifconfig is not installed. As Syncrho stated in his answer, ifconfig has been deprecated for sometime, and is no longer found on a lot of modern distributions.
Here is the best way to get IP address of an device into an variable:
ip=$(ip route get 8.8.8.8 | awk 'NR==1 {print $NF}')
NB Update to support new Linux version. (works also with older)
ip=$(ip route get 8.8.8.8 | awk -F"src " 'NR==1{split($2,a," ");print a[1]}')
Why is it the best?
Hostname -I some times get only the IP or as on my VPS it gets 127.0.0.2 143.127.52.130 2a00:dee0:ed3:83:245:70:fc12:d196
Hostnmae -I does not work on all system.
Using ifconfig may not always give the IP you like.
a. It will fail you have multiple interface (wifi/etcernet) etc.
b. Main IP may not be on the first found interface
Searching of eth0 may fail if interface have other name as in VPS server or wifi
ip route get 8.8.8.8
Tries to get route and interface to Googles DNS server (does not open any session)
Then its easy to get the ip or interface name if you like.
This can also be used to get a ip address of an interface to a host on a multiruted net
my short version. Useful when you have multiple interface and just want the main ip.
host `hostname` | awk '{print $4}'
You can get just awk to do all the parsing of ifconfig:
ip=$(ifconfig | gawk '
/^[a-z]/ {interface = $1}
interface == "eth0" && match($0, /^.*inet addr:([.0-9]+)/, a) {
print a[1]
exit
}
')
Not really shorter or simpler, but it works for me:
ip=$(ip addr show eth0 | grep -o 'inet [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+' | grep -o [0-9].*)
The following works on Mac OS (where there is no ip commnand or hostname options):
#!/bin/bash
#get interface used for defalt route (usually en0)
IF=$(route get default |grep 'interface' |awk -F: '{print $2}');
#get the IP address for inteface IF
#does ifconfig, greps for interface plus 5 lines, greps for line with 'inet '
IP=$(ifconfig |grep -A5 $IF | grep 'inet ' | cut -d: -f2 |awk '{print $2}');
#get the gateway for the default route
GW=$(route get default | awk '/gateway:/ {print $2}');
ifconfig | grep -oP "(?<=inet addr:).*?(?= Bcast)"
When using grep to extract a portion of a line (as some other answers do), perl look-ahead and look-behind assertions are your friends.
The quick explanation is that the first (?<=inet addr:) and last (?= Bcast) parenthesis contain patterns that must be matched, but the characters that match those patters won't be returned by grep, only the characters that are between the two patterns and match the pattern .*? that is found between the sets of parenthesis, are returned.
Sample ifconfig output:
eth0 Link encap:Ethernet HWaddr d0:67:e5:3f:b7:d3
inet addr:10.0.0.114 Bcast:10.0.0.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1392392 errors:0 dropped:0 overruns:0 frame:0
TX packets:1197193 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1294730881 (1.2 GB) TX bytes:167208753 (167.2 MB)
Interrupt:18
This will extract your IP address from the ifconfig output:
ifconfig | grep -oP "(?<=inet addr:).*?(?=Bcast)"
To assign that to a variable, use this:
ip=$(ifconfig | grep -oP "(?<=inet addr:).*?(?=Bcast)")
A slightly more in depth explanation:
From man grep:
-o Print only the matched (non-empty) parts of matching lines, with each such part on a separate output line.
-P Interpret the pattern as a Perl regular expression. This is highly experimental and ‘grep -P’ may warn of unimplemented features.
From permonks.org:
(?<=pattern) is a positive look-behind assertion
(?=pattern) is a positive look-ahead assertion
-o Tells grep to only return the portion of the line that matches the pattern. The look-behinds/aheads are not considered by grep to be part of the pattern that is returned. The ? after .* is important since we want it to look for the very next look-ahead after the .* pattern is matched, and not look for the last look-ahead match. (This is not needed if we added a regex for the IP address instead of .*, but, readability).
I am using
IFACE='eth0'
IP=$(ip -4 address show $IFACE | grep 'inet' | sed 's/.*inet \([0-9\.]\+\).*/\1/')
The advantage of this way is to specify the interface (variable IFACE in the example) in case you are using several interfaces on your host.
Moreover, you could modify ip command in order to adapt this snippet at your convenience (IPv6 address, etc).
I think the most reliable answer is :
ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | awk -F: '{print $2}' | awk '{print $1}' | head -1
AND
hostname -I | awk -F" " '{print $1}'
because when you don't use head -1 it shows all ips....
In my script i did need only the network part of the IP, so I did it like that
local=$(hostname -I | awk '{print $2}' | cut -f1,2,3 -d".")
Where the cut -f1,2,3 -d"." can be read as "get first 3 parts separated by commas"
To change interfaces just change $2 to your interface number, to get whole IP remove cut.
In trying to avoid too many pipes, work on various linuxes, set an exit code, and avoiding ifconfig or other packages, I tried the whole thing in awk:
ip addr show | awk '
BEGIN {FS="/"}
/^[0-9]+: eth[0-9]+.*UP*/ {ss=1}
ss==1 && /^ +inet / {print substr($1,10); exit 0}
END {exit 1}'
and note that a particular interface can be specified after "ip addr show" if you don't want just the first eth interface. And adapting to ipv6 is a matter of looking for "inet6" instead of "inet"...
On mac osx, you can use ipconfig getifaddr [interface] to get the local ip:
$ ipconfig getifaddr en0
192.168.1.30
$ man ipconfig
DESCRIPTION
ipconfig is a utility that communicates with the IPConfiguration agent to
retrieve and set IP configuration parameters. It should only be used in
a test and debug context. Using it for any other purpose is strongly
discouraged. Public API's in the SystemConfiguration framework are cur-
rently the only supported way to access and control the state of IPCon-
figuration.
...
getifaddr interface-name
Prints to standard output the IP address for the first net-
work service associated with the given interface. The output
will be empty if no service is currently configured or active
on the interface.
In my case I had some more interfaces in list before eth0. By this command you can get ip4 address for any interface. For that you need to change eth0 to interface that you need.
/sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{print $1}'
The "eth3" is optional (useful for multiple NIC's)
ipaddress=`ip addr show eth3 | grep 'inet ' | awk '{ print $2}' | cut -d'/' -f1`
If by "my ip address" you mean "the IP address my machine will use to get to the public Internet to which I am connected", then this very tidy JSON answer may work for you, depending on what O/S your machine runs:
ip=$( ip -j route get 8.8.8.8 | jq -r '.[].prefsrc' )
It does require an ip command that produces JSON output (some say the BusyBox ip command cannot do this), the CLI jq parser that can extract fields from JSON input, and your machine has to know how to get to the public IP at 8.8.8.8.
If you want the IP address your machine would use to get to some other place, such as a local network, put that other IP in place of the public IP 8.8.8.8, e.g.
ip=$( ip -j route get 192.168.1.1 | jq -r '.[].prefsrc' )
ip=$( ip -j route get 10.1.2.3 | jq -r '.[].prefsrc' )
If you only have one interface, then most any non-localhost IP address should work to get your IP address.
Parsing the JSON output with jq is so much simpler than all those complex examples with sed, awk, and grep, but the more complex examples do use tools that are present by default on almost all Unix/Linux/BSD systems.
assuming you have something like curl or wget, then one easy way to get external IP addresses with no downstream parsing necessary would be :
— (wildcard syntax for wget might differ)
curl -w '\n\n%{url_effective}\n\n' -s 'http://api{,6}.ipify.org'
98.xxx.132.255
http://api.ipify.org/
2603:7000:xxxx:xxxx:xxxx:c80f:1351:390d
http://api6.ipify.org/
Yielding both IPv4 and IPv6 addresses in one shot

How to Grab MAC Address of Active Ethernet Connection in Bash Script?

Simple Question:
How do I grab the MAC address of the active Ethernet connection in a bash script?
I currently have:
set - `/sbin/ifconfig eth0 | head -1`
MAC=$5
Which outputs the MAC address of the eth0, but if it's eth1 that's active, I want that instead.
Could I beforehand execute ifconfig | grep inet but that wouldn't tell me which interface is active, just that one is active. I need to grab the line above it to tell me which one is the active connection.
Any help would be much appreciated.
Thank you!
Found the answer:
set - `ifconfig | grep -B 1 inet | head -1`
MAC=$5
I grep'd the inet string and returned the line before. Then use head to grab the first line.
you could do something like this
ifconfig | awk '/eth/ { print $5 }'
also an option... depending on user may need to specify /sbin/ifconfig in the xargs
route | awk '/default/ { print $NF }' | xargs -I {} ifconfig {} | awk '/HWaddr/ { print $5 }'

Resources