How do I extract data from nmblookup in bash shell script?
Linux - GeneralThis 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
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
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?
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.
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?
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.
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.
@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
@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.
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.
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
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.
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?
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'.
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
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
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.