LinuxQuestions.org
Register a domain and help support LQ
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - General
User Name
Password
Linux - General This Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.

Notices

Reply
 
Search this Thread
Old 10-06-2009, 11:44 AM   #1
utahnix
Member
 
Registered: Dec 2006
Location: Utah, USA
Distribution: openSUSE
Posts: 72

Rep: Reputation: 15
How do I extract data from nmblookup in bash shell script?


Okay...

I am working on a BASH shell script that does a scan of a subnet with nmap and returns the "live" IP's in the specified range. That part works great.

It's then supposed to query each "live" IP for it's NetBIOS hostname using nmblookup (I've got a Linux server playing PDC for a bunch of Windows workstations - all at a remote site). The problem is, I'm having trouble getting the data out of the nmblookup output.

Once I have the IP, I do something like this:
nmblookup -A <ip_address>

In my script, <ip_address> is naturally replaced with a variable. The problem is, I get output like this (from nmblookup):

Code:
        PCNAME          <00> -         M <ACTIVE>
        OFFICEDOMAIN    <00> - <GROUP> M <ACTIVE>
        PCNAME          <20> -         M <ACTIVE>
        OFFICEDOMAIN    <1e> - <GROUP> M <ACTIVE>

        MAC Address = xx-xx-xx-xx-xx-xx
What I need to do is extract 'PCNAME' and stuff it in a variable. Naturally 'PCNAME' is going to be different each time.

I would imagine awk would do the job, and maybe even sed... but I'm not super savvy with either. I've used perl in the past (esp for one liners), but my perl skills are awfully rusty. I've tried a number of things, and none of them worked.

I tried using grep and cut, but that didn't go well either. I thought perhaps I could use those two to get my variable out, and then use sed to remove the whitespace... but again, no go. I'm obviously doing something wrong.

So is there an easy and efficient way to get this data out?
 
Old 10-06-2009, 12:17 PM   #2
lutusp
Member
 
Registered: Sep 2009
Distribution: Fedora
Posts: 835

Rep: Reputation: 101Reputation: 101
Quote:
Originally Posted by utahnix View Post
Okay...

I am working on a BASH shell script that does a scan of a subnet with nmap and returns the "live" IP's in the specified range. That part works great.

It's then supposed to query each "live" IP for it's NetBIOS hostname using nmblookup (I've got a Linux server playing PDC for a bunch of Windows workstations - all at a remote site). The problem is, I'm having trouble getting the data out of the nmblookup output.

Once I have the IP, I do something like this:
nmblookup -A <ip_address>

In my script, <ip_address> is naturally replaced with a variable. The problem is, I get output like this (from nmblookup):

Code:
        PCNAME          <00> -         M <ACTIVE>
        OFFICEDOMAIN    <00> - <GROUP> M <ACTIVE>
        PCNAME          <20> -         M <ACTIVE>
        OFFICEDOMAIN    <1e> - <GROUP> M <ACTIVE>

        MAC Address = xx-xx-xx-xx-xx-xx
What I need to do is extract 'PCNAME' and stuff it in a variable. Naturally 'PCNAME' is going to be different each time.

I would imagine awk would do the job, and maybe even sed... but I'm not super savvy with either. I've used perl in the past (esp for one liners), but my perl skills are awfully rusty. I've tried a number of things, and none of them worked.

I tried using grep and cut, but that didn't go well either. I thought perhaps I could use those two to get my variable out, and then use sed to remove the whitespace... but again, no go. I'm obviously doing something wrong.

So is there an easy and efficient way to get this data out?
No, not really. The problem is that you cannot say in advance what the data will look like. Sometimes nmblookup won't be able to provide the list you expect, sometimes the list will look different than you expect.

The other problem is that the output is multi-line, which eliminates line-oriented solutions like sed.

All I can say is, catalog all the possible responses from nmblookup and deal with all of them. For this you need more coding skills. IOW you have bitten off more than you can comfortably chew, but you could certainly learn how to solve this problem.
 
Old 10-06-2009, 01:02 PM   #3
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947
Quote:
Originally Posted by lutusp View Post
The other problem is that the output is multi-line, which eliminates line-oriented solutions like sed.
That's not entirely true. Sed can operate over multiple lines. It's just a bit more tricky to do so. How difficult it is depends on just what you're trying to extract.

Of course, whether you use sed or awk or whatever, the real requirement for a job like this is that first you have to find some kind of unique regular pattern to match. If you can determine that the data field you need always appears 2 lines after a certain fixed string, for example, or always appears at the beginning of a line and has 8-10 characters (and no other line does), or something like that, then it should be possible to come up with some way, though not necessarily a simple one, to extract it.

You may need to use more than one pattern match to catch all the different variations you could encounter in the input. Just make sure that whatever pattern(s) you use can uniquely identify the data field you want without any false negatives or false positives.

Also, are there any options you can use in nmblookup to output the data in a more convenient format? Or are there any other tools you can use to provide the same information?
 
1 members found this post helpful.
Old 10-06-2009, 11:39 PM   #4
chrism01
Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 6.5, Centos 5.10
Posts: 16,269

Rep: Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028
Given it's a multi-line output, and the results will vary if eg not a nmb host or whatever, then yes, catalogue all the expected result set types and figure how to match them. Allow for 'unmatched' ie one you didn't know could happen.

I'd personally do it in Perl, probably using a piped open or IPC::Open2 or IPC::Open3 .
If I had to do it in shell, the easiest way would be to redirect the output into a temp file eg nmblookup.dat & then parse the file.
Trying to do it on the fly in bash is tricky.

PS good Perl examples/howto
http://perldoc.perl.org/
http://www.perlmonks.org/?node=Tutorials
 
1 members found this post helpful.
Old 10-07-2009, 01:57 AM   #5
lutusp
Member
 
Registered: Sep 2009
Distribution: Fedora
Posts: 835

Rep: Reputation: 101Reputation: 101
Quote:
Originally Posted by David the H. View Post
That's not entirely true. Sed can operate over multiple lines.
Yes, and one can do Calculus with an abacus -- it's just very, very difficult. The OP is much better off using a solution in which multi-line matches are more intuitive, readable and understandable than is sed when processing multi-line tasks.
 
Old 10-07-2009, 02:35 AM   #6
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,546
Blog Entries: 28

Rep: Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176
How about this
Code:
<whatever nmbscan command, with output redirected to nmbscan.out> 
PCNAME_00=''
PCNAME_20=''
while read line
do 
    array=( $line )
    case "${array[1]}" in
        '<00>' )
            PCNAME_00="'${array[0]}'"
            ;;
        '<20>' )
            PCNAME_20="'${array[0]}'"
            ;;
    esac
done < nmbscan.out
echo "PCNAME_00: '$PCNAME_00', PCNAME_20: '$PCNAME_20'"
 
1 members found this post helpful.
Old 10-07-2009, 03:13 AM   #7
zhjim
Senior Member
 
Registered: Oct 2004
Distribution: Debian Squeeze x86_64
Posts: 1,446
Blog Entries: 11

Rep: Reputation: 182Reputation: 182
@catkin
If the output stays like the provided example your example would print out the second line with officegroup and group. It also has the <00> in it.

I'd go with some awk and would distinguish the line depending on the numbers of fields.
Line 1 with the PCNAME has 5 fields where OFFICEGROUP lines have 6 fields. As long this holds true you could do something like this

Code:
awk { if (NF == 5 ) print $1
and you should get the PCNAME. Maybe do a grep "<00>" beforehand so you only have to awk two lines.

Nother thing if you can be sure that the PCNAME always is the first line go with
Code:
head -n 1
 
1 members found this post helpful.
Old 10-07-2009, 04:01 AM   #8
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,546
Blog Entries: 28

Rep: Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176
Quote:
Originally Posted by zhjim View Post
@catkin
If the output stays like the provided example your example would print out the second line with officegroup and group. It also has the <00> in it.
Ooops! Refined version (I have also taken out some single quotes that should not have been there)
Code:
<whatever nmbscan command, with output redirected to nmbscan.out> 
PCNAME_00=''
PCNAME_20=''
while read line
do 
    array=( $line )
    case "${array[1]}" in
        '<00>' )
            if [[ "${array[0]}" = 'M" ]]; then
                PCNAME_00="${array[0]}"
            fi
            ;;
        '<20>' )
            PCNAME_20="${array[0]}"
            ;;
    esac
done < nmbscan.out
echo "PCNAME_00: '$PCNAME_00', PCNAME_20: '$PCNAME_20'"
The basic framework can be refined with further if-else or case-esac commands, as appropriate, to deal with all the output line types from nmbscan.
 
Old 10-07-2009, 07:43 AM   #9
zhjim
Senior Member
 
Registered: Oct 2004
Distribution: Debian Squeeze x86_64
Posts: 1,446
Blog Entries: 11

Rep: Reputation: 182Reputation: 182
Beside of a little typo I don't understand why the improved version would print the PCNAME. M is also in both lines and not realy array[0] but array[3] inside the PCNAME line.

Code:
    case "${array[1]}" in
        '<00>' )
            if [[ "${array[0]}" = 'M" ]]; then
                PCNAME_00="${array[0]}"
            fi
            ;;
        '<20>' )
            PCNAME_20="${array[0]}"
            ;;
    esac
I guess you meant array[3] inside the '<00>' if statement. I would agree on that And the PCNAME would be printed.

The typo I mentioned is right before the M or is it after? from the escape char you used I'd say its before

Code:
if [[ "${array[0]}" = 'M" ]]; then
Code:
if [[ "${array[0]}" = "M" ]]; then
None the less its great input you gave and a nice and elegant solution.
 
Old 10-07-2009, 07:54 AM   #10
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,546
Blog Entries: 28

Rep: Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176
Quote:
Originally Posted by zhjim View Post
I guess you meant array[3] inside the '<00>' if statement. I would agree on that And the PCNAME would be printed.

The typo I mentioned is right before the M or is it after?
Correct regards the array subscript and either double or single quotes would work but single are the saner choice. One of each definitely won't do! Sorry about the errors.

EDIT: actually the errors were *cough* *cough* a deliberate challenge

Last edited by catkin; 10-07-2009 at 07:56 AM.
 
Old 10-07-2009, 08:06 AM   #11
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947
Quote:
Originally Posted by lutusp View Post
Yes, and one can do Calculus with an abacus -- it's just very, very difficult. The OP is much better off using a solution in which multi-line matches are more intuitive, readable and understandable than is sed when processing multi-line tasks.
And as I said, it depends on exactly what you're trying to match. Matching one line and then grabbing something from the line immediately following it isn't all that hard to do. But if the data string you want can itself span multiple lines, for example, then yes, there are often better tools you can use.

Sed may not always be the ideal choice for multi-line matches, but it's not really as bad as you're making it sound. It's often better than awk in such cases, at the very least.
 
Old 10-07-2009, 08:10 AM   #12
zhjim
Senior Member
 
Registered: Oct 2004
Distribution: Debian Squeeze x86_64
Posts: 1,446
Blog Entries: 11

Rep: Reputation: 182Reputation: 182
Quote:
Originally Posted by catkin View Post
EDIT: actually the errors were *cough* *cough* a deliberate challenge
And we all love them challenges
 
Old 10-07-2009, 04:46 PM   #13
utahnix
Member
 
Registered: Dec 2006
Location: Utah, USA
Distribution: openSUSE
Posts: 72

Original Poster
Rep: Reputation: 15
Okay, hmm... lots of things to consider.

I can probably grep the first line out of the file. I know that's assuming a little, but I can live with that.

At one point, I was able to get the name out, but it had all this white space on the sides. How would I use sed to remove the white space from a single line?

Or, considering the perl factor. If I honed that data down to one line with grep, is there a one-liner (i.e. perl -pe "<CODE>") that would yank that variable name from the line? And if I could get it out, how do I stick the output from that perl one-liner and stuff it back into a BASH perl script?

Help thus far is appreciated... any thoughts on this post?
 
Old 10-07-2009, 11:45 PM   #14
chrism01
Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 6.5, Centos 5.10
Posts: 16,269

Rep: Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028
If you only had one line of data, use awk,; when it picks a field eg $3, doesn't care how much whitespace exists in between each non-whitespace value eg

Code:
  asd fgh

is the same as

asd        fgh
to awk; $1 is still 'fgh'. That's its advantage over 'cut'.
 
Old 10-08-2009, 03:32 AM   #15
zhjim
Senior Member
 
Registered: Oct 2004
Distribution: Debian Squeeze x86_64
Posts: 1,446
Blog Entries: 11

Rep: Reputation: 182Reputation: 182
Quote:
Originally Posted by utahnix View Post
I can probably grep the first line out of the file. I know that's assuming a little, but I can live with that.
If you only want the first line go with head -n 1. I bet to grep some unkown thing is too much even for grep xD.

Quote:
Originally Posted by utahnix View Post
At one point, I was able to get the name out, but it had all this white space on the sides. How would I use sed to remove the white space from a single line?

Or, considering the perl factor.
Help thus far is appreciated... any thoughts on this post?
This also goes into the direction of David the H.
Always remember why there are so many tools (binarys) included with a linux distribution. They all do one thing very good. But this also leaves the challenge to the user which tool to use. Obvious the tool that fullfils the task (cause each and every tool just does it best )
So to make my point across and illustrate what I want to say lets take a look at the first line of the man pages of all the tools mentioned through out this thread.

Code:
grep, egrep, fgrep, rgrep - print lines matching a pattern
So if we don't have a pattern we can't realy use grep

Code:
sed - stream editor for filtering and transforming text
okay somehow we want to filter but we absolutly don't want to transform text. Makes it on the list

Code:
mawk - pattern scanning and text processing language
okay same aplies here like it does to grep put also one point for awk cause it process text. Makes it on the list

Code:
head - output the first part of files
If we dare we consider the first line to be hostname. So this is a total match.

Code:
cut - remove sections from each line of files
this would be good when we found our line. (Just summing up not taking experience into it)

I know this is overkill. I Just wanted to see you all how many tools there are and the more you know the better the chances that you'll find the right one for the job. It's just like moving when you have a loot of friends. It just flies.

To boil things down. Either take the first line with head -n 1 or do the pattern matching of 5 fields within the PCNAME line. awk or the bash script will both suite you well
 
  


Reply

Tags
bash, extract, hostname, nmap, script, variable


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Help on my Linux Homework ! bash shell script / input-output data etc Bebelindo Programming 2 03-03-2009 12:51 PM
run script to extract data to put to web cghcgh Programming 9 06-10-2008 02:11 AM
awk/perl script for extract data mruknown1 Programming 3 09-11-2007 09:19 AM
awk/perl script for extract data mruknown1 Linux - Newbie 2 09-11-2007 04:42 AM
How to extract data and for loop it into an array? (shell) WeiSomething Programming 6 11-17-2006 03:27 AM


All times are GMT -5. The time now is 05:00 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration