One for the Veterans of BASH and Command Line Wizards

ally_ukally_uk Member Posts: 1,145 ■■■■□□□□□□
Quick question for the Linux Vets:

If I run the following command ifconfig | grep -in inet

I get a output of 4 lines of information on my screen where the word 'inet' appears the question is how do I cut this output down and get it to show a specific item. for example the ip address.

So how can I pipe the command further to narrow the results down? do I need awk? Sed? regex? cut?

Enlighten me oh mighty gods :)

The goal is to store the command as a variable to display the IP Address :) so I can run it in a script
Microsoft's strategy to conquer the I.T industry

" Embrace, evolve, extinguish "

Comments

  • lsud00dlsud00d Member Posts: 1,571
    Yes, awk will let you choose what 'column' you want to display. The default awk delimiter (output field separator or OFS) is " ", aka a space. You can change awk to parse on whatever delimiter you want, which can commonly be a colon, semicolon, or comma. Say for instance, parsing a csv.

    Edit: here's a good article on awk's built in variables. Awk is ridiculously powerful.

    8 Powerful Awk Built-in Variables – FS, OFS, RS, ORS, NR, NF, FILENAME, FNR

    Follow up edit: there are several ways you can pursue this so you don't get junk data from grep, unless you literally want all IP's from ifconfig.

    1. awk '{print $3}' (print 3rd column in accordance with the default OFS)
    2. awk '{print $3}' | grep "^192.*" (further refine your search to IP's starting with 192. [or whatever IP/range you're looking for])
    3. You can chain grep's together by 'item1\|item2', so if you're looking for IP's starting with multiple ranges, the \| acts as an 'and' operator, i.e. grep "^192.*\|^127.*"
  • ally_ukally_uk Member Posts: 1,145 ■■■■□□□□□□
    Can you post up the awk expression added to my original command so I can get a feel as to how it looks like.
    Microsoft's strategy to conquer the I.T industry

    " Embrace, evolve, extinguish "
  • lsud00dlsud00d Member Posts: 1,571
    Sure, I was just adding on to what you started (although I'm not sure why you include line numbers?)

    ifconfig | grep -in inet | awk '{print $3}'

    is the basic form. This will print you the column of IP's, however when I checked it in my VM I got my DHCP IPv4/IPv6, then lo (loopback) IPv4/IPv6 addresses (aka home).

    You can also grep for 'broadcast' because that will get you whatever ethX adapter's IPv4 address you want, but there are further refining steps going that route as well.

    Command line is about efficiency, hence the bit I added about chaining grep's.

    Edit: Not to confuse you, but without -n you would print $2 (the second column) with awk because the -n (numbers) introduces a new column
  • ally_ukally_uk Member Posts: 1,145 ■■■■□□□□□□
    Awesome stuff my man :) you have made my day as for the grep -n it's a habit I always do it for some reason lol whoops

    Thank you for the explanation on awk though helped me alot
    Microsoft's strategy to conquer the I.T industry

    " Embrace, evolve, extinguish "
  • ally_ukally_uk Member Posts: 1,145 ■■■■□□□□□□
    What I have that does the job ifconfig | grep -i inet | awk '{print $2}' | grep 192 not sure if this could be shortened? :) gives me a result of addr: 192.168.115.31
    Microsoft's strategy to conquer the I.T industry

    " Embrace, evolve, extinguish "
  • lsud00dlsud00d Member Posts: 1,571
    Sure, you can shorten it to:

    ifconfig | awk '/192/ {print $2}'

    This is the quickest way to achieve what you want--the /.../ acts like grep [does a regex search, checkout the man page for awk] and if awk finds a line that matches, then it prints the column you specified. In this case, 192 matches the IPv4 address you want so it prints column 2, which is the IPv4 address itself.
  • hiddenknight821hiddenknight821 Member Posts: 1,209 ■■■■■■□□□□
    Not a god, but I can help too.

    With my Google-fu skill, I was able to find what you're looking for. I found it on Stackoverflow in the third answer. It seems to answer your question in the simplest term possible. IMO, I think it's the answer's the best I've seen so far as I've tested it. I'm sure it'd run much faster than chaining the commands with tr, cut, and sed.
    ifconfig | awk '/inet addr/ {gsub("addr:", "", $2); print $2}'
    

    With the above command, you'd only get the IP addresses. What lsud00d suggested may only work for private addresses, but this command works for any IP address appears after the 'inet addr:" field.

    To give you a breakdown here, AWK can work like grep, but it's very powerful. The first thing after the awk command, "/inet addr/", would match any line in the 'ifconfig' output containing 'inet addr'. gsub() is a built-in AWK function. The curly bracelets area is where the AWK script gets executed, and anything outside of the bracelet are for the pre-assignments and pre-execution instructions, and are usually placed before the bracelets. gsub() works pretty much like sed. In this case, we're substituting "addr:" with a null character. Technically, we're deleting "addr:" from the line here: ("addr:", "", $2).

    Before I get ahead of myself here, we need to understand what 'print $x' does in an AWK script. It simply print the Xth field in the line. By default, the delimiter is always white space. To print the entire line in AWK, you'd use 'print $0'.

    You can print the "BEFORE" output using the below command so you can understand better what has changed:
    ifconfig | awk '/inet addr/  {print $0}'
    

    Now to finalize what's happening here, in the '{gsub("addr:", "", $2); print $2}' , the third part of the gsub() function is the target: gsub(regexp, replacement, target).

    sub(r,t,s)

    substitutes t for the first occurrence of the regular expression r in the string s. If s is not given, $0 is used.


    At this point, I believe this is pretty much self-explanatory. I hope this helps. Here's a good read on Sed and AWK. You can't go wrong with this old '97 edition that still works. It's an easy read and not too long, IMO.


  • lsud00dlsud00d Member Posts: 1,571
    @hiddenknight821, great point with gsub, however you'd still have to filter for either 1) the IP's you want or 2) the IP's you don't want. Also, the Fedora ifconfig implementation (the VM I hopped in to test this out) doesn't list "addr" in its output...food for thought for both you and I as we advise people on the interwebz of how best to proceed icon_wink.gif
  • hiddenknight821hiddenknight821 Member Posts: 1,209 ■■■■■■□□□□
    @lsud00d, thanks for catching that. I was only trying to accomplish what the OP initally wanted:

    ally_uk wrote: »
    I get a output of 4 lines of information on my screen where the word 'inet' appears the question is how do I cut this output down and get it to show a specific item. for example the ip address.


    The goal is to store the command as a variable to display the IP Address so I can run it in a script


    So I was not concerned with what the IP addresses are as I'm trying to stick with the objective and not make assumptions. Although, your solution will work for any IP address being regexed.


    I didn't realize Fedora will give different output, but if you're running the latest distro, I believe ifconfig command is now obsolete, and we're encouraged to use the 'ip addr show' command instead. I don't have Fedora with me that I can spin up right now as I'm typing this. I'm assuming the 'ifconfig' may have been sym-linked to the aforementioned command, which may be why the output is different.

    ^^
    This is exactly why we always want the raw outputs when people are asking those type of questions, so we can achieve the end result without going back and forth. icon_rolleyes.gif
  • lsud00dlsud00d Member Posts: 1,571
    Another good point about ifconfig deprecation...I've been out of the *nix game for a bit. But (and I didn't remember this until running it) I'm getting the /x netmask notation (/24 in this case), i.e.

    inet 192.168.44.164/24

    so that would require another pipe to filter out. I haven't tried in CentOS, Ubuntu, etc to check those distro's output.

    Alas, most importantly
    This is exactly why we always want the raw outputs when people are asking those type of questions, so we can achieve the end result without going back and forth.

    ^
  • ally_ukally_uk Member Posts: 1,145 ■■■■□□□□□□
    ifconfig | grep -i inet\ addr | sed '2d' | awk '{print $2}' - is another way of just showing the IP Address line ;)

    Here is another question when you are building up long command lines like the above is there a way to copy the command or save it as a variable to be used later in a script? am I right in thinking command substitution?
    Microsoft's strategy to conquer the I.T industry

    " Embrace, evolve, extinguish "
  • YFZbluYFZblu Member Posts: 1,462 ■■■■■■■■□□
    My derpy contribution for those not elite enough for AWK or SED (like me):
    ifconfig <interface name> |grep -o -P "([0-9]{1,3}\.){3}[0-9]{1,3}" |head -1
    
    ally_uk wrote: »
    Here is another question when you are building up long command lines like the above is there a way to copy the command or save it as a variable to be used later in a script? am I right in thinking command substitution?

    I have a one-off script that runs daily to check if my public-facing IP address has changed. What I do is write the current public IP address to a hidden text file...when the script runs, it opens that file to use as a comparison. If the IP has changed, the file is overwritten with the new address and it sends me an email. If the IP hasn't changed, it just exits. Writing a variable to a text file probably isn't ideal for anything more than a one-off...Folks here will probably have a better solution for you...just my two cents.
  • ally_ukally_uk Member Posts: 1,145 ■■■■□□□□□□
    What I mean is when you run a command in the shell and it's a long complicated one you can recall the command using history but how can I
    take this process further? and copy the command on the screen into a blank text file? where I can then assign it as a variable to be used in a script?

    Do I redirect? or is there such a thing as a copy? I know you can use cp for directories and files.

    This is one for the Bash gods I think... :) lol
    Microsoft's strategy to conquer the I.T industry

    " Embrace, evolve, extinguish "
  • hiddenknight821hiddenknight821 Member Posts: 1,209 ■■■■■■□□□□
    It's not that difficult as it requires some 'out-of-the-box' thinking. If you are using a console screen without the GUI where you can't highlight the selection and paste it, then you can copy the command you typed and have it redirected to a file.

    Let's say I want to copy the following command at the prompt I typed: lspci | grep intel | cut -f1

    I'd simply press UP to the commands I wanted in the history, then I'd use CTRL+A to quickly move the cursor to the beginning of the line or CTRL+E for the end of the line. I'd simply enclosed it with a pair of single or double quote. You'd have to be careful not to let it escape or else you'd have to use escape characters. Here's the end result that will append the command to a file rather than overwriting it:

    echo 'lspci | grep intel | cut -f1' >> filename.

    That's it.
  • ally_ukally_uk Member Posts: 1,145 ■■■■□□□□□□
    Thank you for the above, taking it one step further :) this one is really for the BASH gods is there a way to paste a command from the terminal onto a specific line in a text file?


    i.e created a huge command with loads of pipes and regex at the bash prompt.

    I want this to be copied to a text file say test.sh for example. but I want the above command to be copied to a specific line within this file

    For example within test.sh on line 3 is where I wish to declare a variable with the command I created earlier.

    Many thanks how could this be done?

    Sed? copy?
    Microsoft's strategy to conquer the I.T industry

    " Embrace, evolve, extinguish "
  • DoubleNNsDoubleNNs Member Posts: 2,015 ■■■■■□□□□□
    How about a loop? Increment a counter until you get to the line you want. Then insert the line.
    Or break the file into 2 parts - above and below the line. Then cat the top part + new line + bottom part.

    It'd be easier to work up a solution w/ a more concrete example tho. And I'm sure the simplest solution would involve a short sed or awk script.
    Goals for 2018:
    Certs: RHCSA, LFCS: Ubuntu, CNCF CKA, CNCF CKAD | AWS Certified DevOps Engineer, AWS Solutions Architect Pro, AWS Certified Security Specialist, GCP Professional Cloud Architect
    Learn: Terraform, Kubernetes, Prometheus & Golang | Improve: Docker, Python Programming
    To-do | In Progress | Completed
  • ally_ukally_uk Member Posts: 1,145 ■■■■□□□□□□
    sed -i '3i lspci | grep intel | cut -f1' FILENAME (3i will insert third line for example)
    Microsoft's strategy to conquer the I.T industry

    " Embrace, evolve, extinguish "
Sign In or Register to comment.