I need some assistance with a python script. I need to search a dhcpd file for host entires, their MAC and IP, and print it in one line. I am able to locate the hostname and IP address but cannot figure out how to get the variables out of the if statement to put in one line. Any suggestions, the code is below:
#!/usr/bin/python
import sys
import re
#check for arguments
if len(sys.argv) > 1:
print "usage: no arguments required"
sys.exit()
else:
dhcp_file = open("/etc/dhcp/dhcpd.conf","r")
for line in dhcp_file:
if re.search(r'\bhost\b',line):
split = re.split(r'\s+', line)
print split[1]
if re.search(r'\bhardware ethernet\b',line):
ip = re.split(r'\s+',line)
print ip[2]
dhcp_file.close()
There are a number of ways that you could go about this. The simplest is probably to initialize an empty string before the if statements. Then, instead of printing split[1] and ip[2], concatenate them to the empty string and print that afterwards. So it would look something like this:
printstr = ""
if re.search...
...
printstr += "Label for first item " + split[1] + ", "
if re.search...
...
printstr += "Label for second item " + ip[2]
print printstr
In the general case, you can give comma-separated values to print() to print them all on one line:
entries = ["192.168.1.1", "supercomputer"]
print "Host:", entries[0], "H/W:", entries[1]
In your particular case, how about adding the relevant entries to a list and then printing that list at the end?
entries = []
...
entries.append(split[1])
...
print entries
At this point you may want to join the 'entries' you've collected into a single string. If so, you can use the join() method (as suggested by abarnert):
print ' '.join(entries)
Or, if you want to get fancier, you could use a dictionary of "string": "list" and append to those lists, depending on they key string (eg. 'host', 'hardware', etc...)
You can also use a flag, curhost, and populate a dictionary:
with open("dhcpd.conf","r") as dhcp_file:
curhost,hosts=None,{}
for line in dhcp_file:
if curhost and '}' in line: curhost=None
if not curhost and re.search(r'^\s*host\b',line):
curhost=re.split(r'\s+', line)[1]
hosts[curhost] = dict()
if curhost and 'hardware ethernet' in line:
hosts[curhost]['ethernet'] = line.split()[-1]
print hosts
Related
I want to make sure argument passed as list has distinct values and comma separated otherwise throw error for any other delimiter like tab, space , semi colon anything.
Case 1-
input -> ['2015-01-01', '2015-02-01', '2015-02-01','2015-03-01']
output -> ['2015-01-01', '2015-02-01','2015-03-01']
Case 2-
input -> ['2015-01-01';'2015-02-01';'2015-02-01';'2015-03-01']
output -> raise exception - please enter comma separated list.
Since there is little information to go on.
Here is a simple solution to what i think it is you are trying to ask:
l1 = []
while True:
user_ = input("> ")
if user_ == "exit":
break
if user_ in l1:
print("already exists")
if user_ not in l1:
l1.append(user_)
print(l1)
print(l1)
Basically this will prevent the user from inputting the same thing twice.
You do not need to worry about the list being in an incorrect format. Lists in python will always have comma separation when user inputs.
If you would like to make sure the user is inputting string in a specific format IE in date form yyyy/mm/dd. You would just need to add another conditional to check that.
Hope this helps.
I am just assuming the expected outcome and input from the comments and answers posted earlier
import re
string_list = ["['2015-01-01';'2015-02-01';'2015-02-01';'2015-03-01']",
"['2015-01-01';'2015-02-01' '2015-02-01';'2015-03-01']",
"['2015-01-01';'2015-02-01' '2015-02-01';'2015-03-01']",
"['2015-01-01','2015-02-01','2015-02-01','2015-03-01']"
]
for i in string_list:
if re.findall(r"\d{4}-\d{2}-\d{2}'[;*&\t\s]{1,}",i):
print('invalid') # raise excpetion here
else:
print(set(i[1:-1].replace("'",'').split(',')))
Output:
invalid
invalid
invalid
set(['2015-03-01', '2015-01-01', '2015-02-01'])
The valid output would be of type set which can be converted to list if required using list()
Something along these lines could cleanup user input, but it will always have the potential for someone to put something unexpected in.
I would take each value separately and append them to a list, myself.
inList = "['2015-01-01';'2015-02-01';'2015-02-01';'2015-03-01']"
delimiters = [",", ";", "\t", "\n", " "]
rem = ["[", "]", '"', "'", " "]
out = []
for delimiter in delimiters:
if delimiter in inList:
for r in rem:
if delimiter == r :break
inList = inList.replace(r, '')
out = inList.split(delimiter)
break
print(out)
I am new to python and with this task I'm trying to learn it. I'd like to get information out of a DNS zone file. The DNS file has the following entries:
something 600 A 192.168.123.45
600 A 192.168.123.46
someelse CNAME something
anotherone A 192.168.123.47
nextone CNAME anotherone
anotherone TXT ( "te asd as as d" )
The goal is to grab the hostnames and IF there is a coresponding TXT entry, I'd like to get the information for that entry as well.
So I started to just work through the file, if I would describe the entries, the Record type is either at [2] or [1] and right after it, I got the IP. So I have something like this for now:
for line in data:
word = line.split()
if len(word) > 2:
if "CNAME" == word[2]:
rectype = "CNAME"
arecord = word[3].replace('.domain.com.', '')
print rectype + " " + arecord
if "CNAME" == word[1]:
rectype = "CNAME"
arecord = word[2].replace('.domain.com.', '')
print rectype + " " + arecord
if "A" == word[2]:
rectype = "A"
print rectype + " " + word[3]
if "A" == word[1]:
rectype = "A"
print rectype + " " + word[2]
okay, so far so good.. but now if I like to get that corresponding TXT record, do I need to work through every line in the document for each line or is their any easier and more efficiernt way to do that?
Part of the beauty of Python is you can write code that reads like English and it uses intuitive operators.
You have a lot of duplicated code. In your example, we can see that anytime a "keyword" pops up, such as A or CNAME then you simply take the next token. Here, I used the in Python keyword which checks if an element is in a collection of some sort. This is a boolean, so if it returns true then I take the next element, ie, tokens[tokens.index(keyword) + 1].
Similarly, in can also be used for string and substring searches. I check to see if "TXT" is in the current line, and if it is, I assume you want everything after it? I use a splice operator to specify the range.
line[line.index("TXT") + 3:] means that I want everything in line after the index line.index("TXT") + 3.
KEYWORDS = ["CNAME", "A"]
for line in data:
tokens = line.split()
if len(tokens) > 2:
record = ""
for keyword in KEYWORDS:
if keyword in tokens:
record = keyword + " " + tokens[tokens.index(keyword) + 1]
if "TXT" in line:
txt_data = line[line.index("TXT") + 3:]
record += "TXT: " + txt_data
print record
I'd recommend you build a dictionary whose keys are identifiers ("anotherone" would be an example from your sample) and whose values are strings (or maybe a list of strings - I'm rusty on DNS and am not sure if multiples are possible).
As you encounter CNAME and A records, add the identifiers as keys into the dictionary and initialize their corresponding values as empty lists. Then when you hit a line with "TXT" in it, lookup that identifier in the dictionary and add the line as value.
I have a file i am trying to replace parts of a line with another word.
it looks like bobkeiser:bob123#bobscarshop.com:0.0.0.0.0:23rh32o3hro2rh2:234212
i need to delete everything but bob123#bobscarshop.com, but i need to match 23rh32o3hro2rh2 with 23rh32o3hro2rh2:poniacvibe , from a different text file and place poniacvibe infront of bob123#bobscarshop.com
so it would look like this bob123#bobscarshop.com:poniacvibe
I've had a hard time trying to go about doing this, but i think i would have to split the bobkeiser:bob123#bobscarshop.com:0.0.0.0.0:23rh32o3hro2rh2:234212 with data.split(":") , but some of the lines have a (:) in a spot that i don't want the line to be split at, if that makes any sense...
if anyone could help i would really appreciate it.
ok, it looks to me like you are using a colon : to separate your strings.
in this case you can use .split(":") to break your strings into their component substrings
eg:
firststring = "bobkeiser:bob123#bobscarshop.com:0.0.0.0.0:23rh32o3hro2rh2:234212"
print(firststring.split(":"))
would give:
['bobkeiser', 'bob123#bobscarshop.com', '0.0.0.0.0', '23rh32o3hro2rh2', '234212']
and assuming your substrings will always be in the same order, and the same number of substrings in the main string you could then do:
firststring = "bobkeiser:bob123#bobscarshop.com:0.0.0.0.0:23rh32o3hro2rh2:234212"
firstdata = firststring.split(":")
secondstring = "23rh32o3hro2rh2:poniacvibe"
seconddata = secondstring.split(":")
if firstdata[3] == seconddata[0]:
outputdata = firstdata
outputdata.insert(1,seconddata[1])
outputstring = ""
for item in outputdata:
if outputstring == "":
outputstring = item
else
outputstring = outputstring + ":" + item
what this does is:
extract the bits of the strings into lists
see if the "23rh32o3hro2rh2" string can be found in the second list
find the corresponding part of the second list
create a list to contain the output data and put the first list into it
insert the "poniacvibe" string before "bob123#bobscarshop.com"
stitch the outputdata list back into a string using the colon as the separator
the reason your strings need to be the same length is because the index is being used to find the relevant strings rather than trying to use some form of string type matching (which gets much more complex)
if you can keep your data in this form it gets much simpler.
to protect against malformed data (lists too short) you can explicitly test for them before you start using len(list) to see how many elements are in it.
or you could let it run and catch the exception, however in this case you could end up with unintended results, as it may try to match the wrong elements from the list.
hope this helps
James
EDIT:
ok so if you are trying to match up a long list of strings from files you would probably want something along the lines of:
firstfile = open("firstfile.txt", mode = "r")
secondfile= open("secondfile.txt",mode = "r")
first_raw_data = firstfile.readlines()
firstfile.close()
second_raw_data = secondfile.readlines()
secondfile.close()
first_data = []
for item in first_raw_data:
first_data.append(item.replace("\n","").split(":"))
second_data = []
for item in second_raw_data:
second_data.append(item.replace("\n","").split(":"))
output_strings = []
for item in first_data:
searchstring = item[3]
for entry in second_data:
if searchstring == entry[0]:
output_data = item
output_string = ""
output_data.insert(1,entry[1])
for data in output_data:
if output_string == "":
output_string = data
else:
output_string = output_string + ":" + data
output_strings.append(output_string)
break
for entry in output_strings:
print(entry)
this should achieve what you're after and as prove of concept will print the resulting list of stings for you.
if you have any questions feel free to ask.
James
Second edit:
to make this output the results into a file change the last two lines to:
outputfile = open("outputfile.txt", mode = "w")
for entry in output_strings:
outputfile.write(entry+"\n")
outputfile.close()
I am writing a Python script that will ask for a file and a name (e.g. "John").
The file contains a whole bunch of lines like this:
...
Name=John
Age=30
Pay=1000
Married=1
Name=Bob
Age=25
Pay=500
Married=0
Name=John
Age=56
Pay=3000
Married=1
...
I want to open this file, ask the user for a name, and replace the pay value for all entries that match that name. So, for example, the user inputs "John", I want to change the Pay for all "John"s to be, say, 5000. The Pay value for other names don't change.
So far, I've opened up the file and concatenated everything into one long string to make things a bit easier:
for line in file:
file_string += line
At first, I was thinking about some sort of string replace but that didn't pan out since I would search for "John" but I don't want to replace the "John", but rather the Pay value that is two lines down.
I started using regex instead and came up with something like this.
# non-greedy matching
re.findall("Name=(.*?)\nAge=(.*?)\nPay=(.*?)\n", file_string, re.S)
Okay, so that spits out a list of 3-tuples of those groupings and it does seem to find everything fine. Now, to do the actual replacement...
I read on another question here on StackOverflow that I can set the name of a grouping and use that grouping later on...:
re.sub(r'Name=(.*?)\nAge=(.*?)\nPay=', r'5000', file_string, re.S)
I tried that to see if it would work and replace all Names with 5000, but it didn't. If it would then I would probably do a check on the first group to see if it matched the user-inputed name or something.
The other problem is that I read on the Python docs that re.sub only replaces the left-most occurrence. I want to replace all occurrences. How do I do that?
Now I am a bit loss of what to do so if anyone can help me that would be great!
I don't think that regex is the best solution to this problem. I prefer more general solutions. The other answers depend on one or more of the following things:
There are always 4 properties for a person.
Every person has the same properties.
The properties are always in the same order.
If these are true in your case, then regex could be ok.
My solution is more verbose, but it isn't depending on these. It handles mixed/missing properties, mixed order, and able to set and get any property value. You could even extend it a little, and support new property or person insertion if you need.
My code:
# i omitted "data = your string" here
def data_value(person_name, prop_name, new_value = None):
global data
start_person = data.find("Name=" + person_name + "\n")
while start_person != -1:
end_person = data.find("Name=", start_person + 1)
start_value = data.find(prop_name + "=", start_person, end_person)
if start_value != -1:
start_value += len(prop_name) + 1
end_value = data.find("\n", start_value, end_person)
if new_value == None:
return data[start_value:end_value]
else:
data = data[:start_value] + str(new_value) + data[end_value:]
start_person = data.find("Name=" + person_name + "\n", end_person)
return None
print data_value("Mark", "Pay") # Output: None (missing person)
print data_value("Bob", "Weight") # Output: None (missing property)
print data_value("Bob", "Pay") # Output: "500" (current value)
data_value("Bob", "Pay", 1234) # (change it)
print data_value("Bob", "Pay") # Output: "1234" (new value)
data_value("John", "Pay", 555) # (change it in both Johns)
Iterate 4 lines at a time. If the first line contains 'John' edit the line that comes two after.
data = """
Name=John
Age=30
Pay=1000
Married=1
Name=Bob
Age=25
Pay=500
Married=0
Name=John
Age=56
Pay=3000
Married=1
"""
lines = data.split()
for i, value in enumerate(zip(*[iter(lines)]*4)):
if 'John' in value[0]:
lines[i*4 + 2] = "Pay=5000"
print '\n'.join(lines)
The following code will do what you need:
import re
text = """
Name=John
Age=30
Pay=1000
Married=1
Name=Bob
Age=25
Pay=500
Married=0
Name=John
Age=56
Pay=3000
Married=1
"""
# the name you're looking for
name = "John"
# the new payment
pay = 500
print re.sub(r'Name={0}\nAge=(.+?)\nPay=(.+?)\n'.format(re.escape(name)), r'Name=\1\nAge=\2\nPay={0}\n'.format(pay), text)
I have a program that logs into a server and issues commands. The results are printed out at the end of the script. The below code shows the script I have created to pass commands through ssh.
import pexpect
ssh_newkey = 'Are you sure you want to continue connecting'
# my ssh command line
p=pexpect.spawn('ssh user#00.00.00.00')
i=p.expect([ssh_newkey,'password:',pexpect.EOF])
if i==0:
print "I say yes"
p.sendline('yes')
i=p.expect([ssh_newkey,'password:',pexpect.EOF])
if i==1:
print "I have entered the password. I will now flip camera through ",
p.sendline("user")
i=p.expect('user#hol-NA:')
p.sendline("cd /opt/ad/bin")
i=p.expect('user#hol-NA:')
p.sendline("./ptzflip")
i=p.expect('user#hol-NA:')
elif i==2:
print "I either got key or connection timeout"
pass
results = p.before # print out the result
print results
The results that the program prints out is:
Value = 1800
Min = 0
Max = 3600
Step = 1
I want to capture the values that are printed out.
In reponse to the questions below. I want to capture eg. 'Value' as a variable and '1800' as its value. I have tried to separate it in a dictionary as mentioned below but I get an error. When I enter:
results_dict = {}
for line in results:
name, val = line.split(' = ')
results_dict[name] = val
I get an error:
Traceback (most recent call last):
File "ptest.py", line 30, in <module>
name, val = line.split(' = ')
ValueError: need more than 1 value to unpack
When I check this code in Python it stores these values as a string. It stores it as:
'/opt/ad/bin$ ./ptzflip\r\nValue = 1800\r\nMin = 0\r\nMax = 3600\r\nStep = 1\r\n'
Can anyone help in this problem. Thanks
Are Value = 1800 etc. the contents of results? And you want to "capture" that?
Do you mean you want to parse those results? Or execute them as python?
If the former you could do something like (untested, unclean, doesn't deal carefully with whitespace):
results_dict = {}
for line in results.splitlines():
try:
name, val = line.split(' = ')
except ValueError:
continue
results_dict[name] = val
This gives you a python dictionary that you can use. If you know that the values are always numbers, you could convert them with int(val) or float(val)... (The try...except ignores lines of the incorrect form; there may be more robust ways to do this, such as if " = " in line)
If you actually want to end up with a variable named Value with the value 1800, you could use eval(results) [or a safer alternative], although this would need to remove lines without the right format first.
do you mean save it to a file?? then try this
open("output.txt","w").write(results)
or when you run the script on the command line:
$ python script.py > output.txt
otherwise, define what you mean by "capture"
After each call to p.expect returns, whatever the child process emitted just before the matched part (any number of lines), and the matched part itself, are accessible as the before and after properties of p -- that's your "capture" for you!
I.e., as the docs put it:
After each call to expect() the before
and after properties will be set to
the text printed by child application.
The before property will contain all
text up to the expected string
pattern. The after string will contain
the text that was matched by the
expected pattern. The match property
is set to the re MatchObject.
The example code in the docs right after this part can be helpful to understand this -- after establishing an FTP session with the interactive ftp client,
child.sendline('ls /pub/OpenBSD/')
child.expect('ftp> ')
print child.before # Print the result of the ls command.
Whenever this happens to me, it's because the string I'm splitting does not have the value I expected. Why not look at it directly?
for line in results:
print line
name, val = line.split(' = ')
results_dict[name] = val
If it were what you think it is, this would work (now in the interpreter):
>>> 'Value = 1800'.split(' = ')
['Value', '1800']