How do I parse the output of getmac command? - python

After doing some research I found out that the best way to get the Ethernet MAC address under windows is the "getmac" command. (getmac module of python does not produce the same!!). Now I want to use this command from within a python code to get the MAC address. I figured out that my code should start something like this:
import os
if sys.platform == 'win32':
os.system("getmac")
do something here to get the first mac address that appears in the results
here is an example output
Physical Address Transport Name
=================== ==========================================================
1C-69-7A-3A-E3-40 Media disconnected
54-8D-5A-CE-21-1A \Device\Tcpip_{82B01094-C274-418F-AB0A-BC4F3660D6B4}
I finally want to get 1C-69-7A-3A-E3-40 preferably without the dashes.
Thanks in advance.

Two things. First of all, I recommend you find ways of getting the mac address more elegantly. This question's answer seems to use the uuid module, which is perhaps a good cross-platform solution.
Having said that, if you want to proceed with parsing the output of a system call, I recommend the use of Python's subprocess module. For example:
import subprocess
output_of_command = subprocess.check_output("getmac")
This will run getmac and the output of that command will go into a variable. From there, you can parse the string.
Here's how you might extract the mac address from that string:
# I'm setting this directly to provide a clear example of the parsing, separate
# from the first part of this answer.
my_string = """Physical Address Transport Name
=================== ==========================================================
1C-69-7A-3A-E3-40 Media disconnected
54-8D-5A-CE-21-1A \Device\Tcpip_{82B01094-C274-418F-AB0A-BC4F3660D6B4}"""
my_mac_address = my_string.rsplit('=', 1)[-1].split(None, 1)[0]
The first split is a right split. It's breaking up the string by the '=' character, once, starting from the end of the string. Then, I'm splitting the output of that by whitespace, limiting to one split, and taking the first string value.
Again, however, I would discourage this approach to getting a mac address. Parsing the human-readable output of command line scripts is seldom advisable because the output can unexpectedly be different than what your script is expecting. You can assuredly get the mac address in a more robust way.

Related

Line terminator adds dot at the end of a line in npm test of Python code

I wanted to learn command line programming using Python.
I saw a to-do challenge on the internet and started to work on it by learning from the web. The challenge is to create a command line interface of a to-do app.
The challenge is titled CoronaSafe Engineering Fellowship Test Problem. Here is the challenge material on Google Drive: https://drive.google.com/drive/folders/1SyLcxnEBNRecIyFAuL5kZqSg8Dw4xnTG?usp=sharing
and there is a GitHub project at https://github.com/nseadlc-2020/package-todo-cli-task/
In the README.md I was instructed to create symbolic link for the batch file todo.bat with the name todo. Now, my first condition is that, when the symbolic link is called from the command prompt without any arguments, it must print some usage tips for the program. Finally, I have to use the npm test command to test the execution.
At the very beginning I got this trouble, whenever I use a print statement, I see a dot • at the end of every string which ends with a new line. For instance,
import sys
import random
args = sys.argv[1:]
if len(args) == 0:
print('Usage :-', end='\n')
print('$ ./todo help # Show usage', end='')
The above statements when executed without arguments gives the output,
Usage :-.
$ ./todo help # Show usage
Here, I noticed that for the first print statement ends with a newline, the string ends with what looks like a middle dot (•). Whereas, for the second print statement since I override the end parameter with an empty string, no newline character was output, and so the dot is not printed. See the screen shot:
What's wrong, and how can I pass the test? My program does not print a middle dot at all.
The problem seems to be squarely inside the todo.test.js file.
In brief, Windows and Unix-like platforms have different line ending conventions (printing a line in Windows adds two control characters at the end, whilst on Unix-like systems only one is printed) and it looks like the test suite is only prepared to cope with results from Unix-like systems.
Try forcing your Python to only print Unix line feeds, or switch to a free Unix-like system for running the tests.
Alternatively, rename todo.test.js and replace it with a copy with DOS line feeds. In many Windows text editors, you should be able to simply open the file as a Unix text file, then "Save As..." and select Windows text file (maybe select "ANSI" if it offers that, though the term is horribly wrong and they should know better); see e.g. Windows command to convert Unix line endings? for many alternative solutions (many of which vividly illustrate some of the other issues with Windows; proceed with caution).
This seems to be a known issue, as noted in the README.md you shared: https://github.com/nseadlc-2020/package-todo-cli-task/issues/12 (though it imprecisely labels this as "newline UTF encoding issues"; the problem has nothing to do with UTF-8 or UTF-16).
See also the proposed duplicate Line endings (also known as Newlines) in JS strings
I had exactly the same problem.
I replaced:
print(variable_name) # Or print("Your text here")
With:
sys.stdout.buffer.write(variable_name.encode('utf-8')) # To sys.stdout.buffer.write("Your text here".encode('utf-8'))
Now it worked fine in windows.
First write your help string like this
help_string='Usage :-\n$ ./task add 2 hello world # Add a new item with priority 2 and text "hello world" to the list\n$ ./task ls # Show incomplete priority list items sorted by priority in ascending order\n$ ./task del INDEX # Delete the incomplete item with the given index\n$ ./task done INDEX # Mark the incomplete item with the given index as complete\n$ ./task help # Show usage\n$ ./task report # Statistics'
Then print it on the console using
sys.stdout.buffer.write(help_string.encode('utf8'))
This problem occurs due to differences in encoding type of windows and npm tests. Also make sure to avoid any spaces after or before "\n".
Why have multiple prints,when python prints can incorporate new line without having to declare separately, follow example below:
print("Usage :- \n$ ./todo help #Show usage")
Output:
Usage :-
$ ./todo help #Show usage

variable regex python

MyDir = os.getcwd().split(os.sep)[-1]
command = re.search(r"(MyDir)", body).group(1)
etc
hi guys,
am trying to have a python script (on windows)
search my outlook email body for certain words using regex
that works fine, coupled with the rest of the script (not shown)
but the minute i want it to search for a variable, ie MyDir it does nothing when i fire off an email to
myself with the word: documents in the body of the email (documents, being the directory the script is located on this occasion; though should populate the variable with whatever top level directory the script is being run from)
now i have read and seen that re.escape is a method to consider, and have copied lots of different variations, and examples
and adapted it to my scenario, but none have worked, i have built the regex as a string also, still no joy
is there anything in my MyDir "variable" that is throwing the regex search off?
am stumped, its my first python script, so am sure am doing something wrong - or maybe i cant use os.getcwd().split(os.sep)[-1] inside regex and have it not look at the variable but the literal string!
thanks for any help, as i have read through similar regex+variable posts on here but havent worked for me
:)
Try:
command = re.search("(" + re.escape(MyDir) + ")", body).group(1)
You searching for the string MyDir not the variable MyDir. You could use str.format
command = re.search(r"({})".format(MyDir), body).group(1)

Python BeautifulSoup Ampersand issue Mac vs. Linux Ubuntu

I've read that BeautifulSoup has problems with ampersands (&) which are not strictly correct in HTML but still interpreted correctly by most browsers. However weirdly I'm getting different behaviour on a Mac system and on a Ubuntu system, both using bs4 version 4.3.2:
html='<td>S&P500</td>'
s=bs4.BeautifulSoup(html)
On the Ubuntu system s is equal to:
<td>S&P500;</td>
Notice the added semicolon at the end which is a real problem
On the mac system:
<html><head></head><body>S&P500</body></html>
Never mind the html/head/body tags, I can deal with that, but notice S&P 500 is correctly interpreted this time, without the added ";".
Any idea what's going on? How to make cross-platform code without resorting to an ugly hack? Thanks a lot,
First I can't reproduce the mac results using python2.7.1 and beautifulsoup4.3.2, that is I am getting the extra semicolon on all systems.
The easy fix is a) use strictly valid HTML, or b) add a space after the ampersand. Chances are you can't change the source, and if you could parse out and replace these in python you wouldn't be needing BeautifulSoup ;)
So the problem is that the BeautifulSoupHTMLParser first converts S&P500 to S&P500; because it assumes P500 is the character name and you just forgot the semicolon.
Then later it reparses the string and finds &P500;. Now it doesn't recognize P500 as a valid name and converts the & to & without touching the rest.
Here is a stupid monkeypatch only to demonstrate my point. I don't know the inner workings of BeautifulSoup well enough to propose a proper solution.
from bs4 import BeautifulSoup
from bs4.builder._htmlparser import BeautifulSoupHTMLParser
from bsp.dammit import EntitySubstitution
def handle_entityref(self, name):
character = EntitySubstitution.HTML_ENTITY_TO_CHARACTER.get(name)
if character is not None:
data = character
else:
# Previously was
# data = "&%s;" % name
data = "&%s" % name
self.handle_data(data)
html = '<td>S&P500</td>'
# Pre monkeypatching
# <td>S&P500;</td>
print(BeautifulSoup(html))
BeautifulSoupHTMLParser.handle_entityref = handle_entityref
# Post monkeypatching
# <td>S&P500</td>
print(BeautifulSoup(html))
Hopefully someone more versed in bs4 can give you a proper solution, good luck.

subprocess.call vs os.system python

First time questioning here:
I have a need to map a network drive in windows. The location is an internal sharepoint document library.
In the cmd window:
net use g: http://na.com/DMP/DMP/programming/
is successfull --> the command completed succeffuly
os.system('"net use k: http://na.com/DMP/DMP/programming/"')
is also successful.
However i would like to use subprocess.call in the event that the drive is already mapped - i would like to try another drive
call(["net", "use", ":q", '"http://na.com/DMP/DMP/programming/"'])
This fails with "System error 67 has occured. The network name cannot be found"
I have tried many options for the last list item with no luck.
Any idea what I can stuff in there to have this complete successfully or a different method to map drives.
There are at least two problems in your code:
call(["net", "use", ":q", '"http://na.com/DMP/DMP/programming/"'])
First, you've got ":q" where you meant "q:". This might cause the net command to interpret :q as your network location instead of your target drive, which could cause an error 67.
Second, you've got an extra set of quotes around the URL: '"http://na.com/DMP/DMP/programming/"' where you should be using 'http://na.com/DMP/DMP/programming/'. When subprocess builds the string to pass to CreateProcess, it already quotes each of your parameters. So, if you quote them yourself, you end up double-quoting the parameters. There are some cases where this is actually not possible in Windows, so you end up with garbage, but I don't think that's the case here. You will successfully get this quoted string to net, telling it that you want to open either a relative path starting with "http: or a URL with protocol "http, or something like that. Whatever it is, it's not a usable network location, which most likely will cause an error 67.
As Ben pointed out, your system call has a similar problem—you put an extra pair of quotes around the entire string. If you really wanted to figure it out, there probably is some reason that this worked… but I don't think you want to figure it out. Just take it as "I did the wrong thing, but I got lucky", and don't do it that way in the future.
Finally, as the documentation says:
On Windows, an args sequence is converted to a string that can be parsed
This means that, if you already have a working command line for Windows, you're better off just using it as a string, than trying to break it down into a sequence for subprocess to reassemble.
(Keep in mind that this is only true for Windows! On other platforms, instead of building a command line string to pass to a function in the CreateProcess family, subprocess builds an array of strings to pass to a function in the exec family.)
So, just do this:
call("net use g: http://na.com/DMP/DMP/programming/")

Capture output from pexpect

I am having trouble with pexpect. I'm trying to grab output from tralics which reads in latex equations and emits the MathML representation, like this:
1 ~/ % tralics --interactivemath
This is tralics 2.14.5, a LaTeX to XML translator, running on tlocal
Copyright INRIA/MIAOU/APICS/MARELLE 2002-2012, Jos\'e Grimm
Licensed under the CeCILL Free Software Licensing Agreement
Starting translation of file texput.tex.
No configuration file.
> $x+y=z$
<formula type='inline'><math xmlns='http://www.w3.org/1998/Math/MathML'><mrow><mi>x</mi> <mo>+</mo><mi>y</mi><mo>=</mo><mi>z</mi></mrow></math></formula>
>
So I try to get the formula using pexpect:
import pexpect
c = pexpect.spawn('tralics --interactivemath')
c.expect('>')
c.sendline('$x+y=z$')
s = c.read_nonblocking(size=2000)
print s
The output has the formula, but with the original input at the beginning and some control chars at the end:
"x+y=z$\r\n<formula type='inline'><math xmlns='http://www.w3.org/1998/Math/MathML'><mrow><mi>x</mi><mo>+</mo><mi>y</mi><mo>=</mo><mi>z</mi></mrow></math></formula>\r\n\r> \x1b[K"
I can clean the output string, but I must be missing something basic. Is there a cleaner way to get the MathML?
From what I understand you are trying to get this from pexpect:
<formula type='inline'><math xmlns='http://www.w3.org/1998/Math/MathML'><mrow><mi>x</mi> <mo>+</mo><mi>y</mi><mo>=</mo><mi>z</mi></mrow></math></formula>
You can use a regexp instead of ">" for the matching in order to get the expected result. This is the easiest example:
c.expect("<formula.*formula>");
After that, you can access the matched string by calling the match attribute of pexpect:
print c.match
You might also try different regexps, due to the fact that the one I posted is a greedy one and it might hinder your execution time if the formulas are big.

Categories