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']
Related
I wrote a script for system automation, but I'm getting the error described in the title. My code below is the relevant portion of the script. What is the problem?
import csv
import os
DIR = "C:/Users/Administrator/Desktop/key_list.csv"
def Customer_List(csv):
customer = open(DIR)
for line in customer:
row = []
(row['MEM_ID'],
row['MEM_SQ'],
row['X_AUTH_USER'],
row['X_AUTH_KEY'],
row['X_STORAGE_URL'],
row['ACCESSKEY'],
row['ACCESSKEYID'],
row['ACCESSKEY1'],
row['ACCESSKEYID1'],
row['ACCESSKEY2'],
row['ACCESSKEYID2'])=line.split()
if csv == row['MEM_ID']:
customer.close()
return(row)
else:
print ("Not search for ID")
return([])
id_input = input("Please input the Customer ID(Email): ")
result = Customer_List(id_input)
if result:
print ("iD: " + id['MEM_ID']
For the line
line.split()
What are you splitting on? Looks like a CSV, so try
line.split(',')
Example:
"one,two,three".split() # returns one element ["one,two,three"]
"one,two,three".split(',') # returns three elements ["one", "two", "three"]
As #TigerhawkT3 mentions, it would be better to use the CSV module. Incredibly quick and easy method available here.
The error message is fairly self-explanatory
(a,b,c,d,e) = line.split()
expects line.split() to yield 5 elements, but in your case, it is only yielding 1 element. This could be because the data is not in the format you expect, a rogue malformed line, or maybe an empty line - there's no way to know.
To see what line is causing the issue, you could add some debug statements like this:
if len(line.split()) != 11:
print line
As Martin suggests, you might also be splitting on the wrong delimiter.
Looks like something is wrong with your data, it isn't in the format you are expecting. It could be a new line character or a blank space in the data that is tinkering with your code.
Hello I am having a KeyError when searching through a huge file with multiple serial numbers. The issue occurs when ever I am searching through the file and input a serial number that appears twice within the file. I want to search through this text file and print out the serial numbers I need or the user inputs.
This is the error:
if item[param] != correct:
KeyError: 'APN'
Here is a text example of the file I am searching through:
500,SHOWALL
APN=" "
APU=" "
APP=" "
IPD="127.0.0.1"
DSP=1710
IPU="127.0.0.1"
VWD="2"
600,SHOWALL
APN=""
APU=" "
APP=" "
IPD="127.0.0.1"
DSP=1710
IPU="127.0.0.1"
VWD="2"
700,SHOWALL
APN=" "
APU=" "
APP=" "
IPD="127.0.0.1"
DSP=1710
IPU="127.0.0.1"
VWD="2"
500,SHOWALL
APN=""
APU=" "
APP=" "
IPD="127.0.0.1"
DSP=1710
IPU="127.0.0.1"
VWD="2"
since 500 appears twice in the file it will run into a KeyError.
Here is an example of my code:
def process(infile, outfile, keywords):
keys = [[k[0], k[1], 0] for k in keywords ]
endk = None
with open(infile, "rb") as fdin:
with open(outfile, "ab") as fdout:
fdout.write("<" + words + ">" + "\n")
for line in fdin:
if endk is not None:
fdout.write(line)
if line.find(endk) >= 0:
fdout.write("\n")
endk = None
else:
for k in keys:
index = line.find(k[0])
if index >= 0:
fdout.write(line[index + len(k[0]):].lstrip())
endk = k[1]
k[2] += 1
if endk is not None:
raise Exception(endk + " not found before end of file")
return keys
This is the definition process I use for the input file, output file, and the keywords to search through the file. This is the output portion of the code:
while (count < (len(setNames))):
for number, item in enumerate(lst, 0):
print setNames[count]
for param, correct in correct_parameters.items():
if item[param] != correct:
print('{} = {} which is incorrect'.format(param, item[param]))
with open(compareResults, "ab") as fdout:
fdout.write('{}'.format(setNames[count]) + " " + '{} = {} which is incorrect'.format(param, item[param])+ '\n')
count += 1
My goal would be to some how allow the program to output the result twice if the serial number appears twice or more. So even if 500 appears two or more times within my text file. I still want it to print correct all the 500 results.
Here is a link to my full code. I did not post the full thing because it is very convoluted and needs some cleaning up to do before anything.
http://pastebin.com/aCe9N8vW
If any more information is need I will post below.
It sounds like you were not expecting a KeyError to occur. If that is the case, then using item.get() may only hide the error. Consider using try/except:
try:
if item[param] != correct:
report_incorrect()
except KeyError:
print('Expected key {}'.format(param))
Really you should go back through the code and determine why the key doesn't exist.
I attempted to look at the link you provided, but the code is not yet organized enough for me to easily read. It would help to provide some comments at the top about what it is supposed to do. For example,
"""This code reads an input log file and a configuration file.
For each serial number in the configuration file, it outputs how
many times it occurs in the log file.
"""
Also it would help to organize more things into functions and perhaps classes, again with comments about the goal of each. Perhaps when the code is cleaned up, the problem will go away.
You can try like this,
if item.get(param) != correct:
KeyError:
Raised when a mapping (dictionary) key is not found in the set of existing keys.
If you don't want to have an exception, you can use the get() method
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
I have an assessment to do, and here's my code so far:
number1 = input("Number1? ")
number2 = input("Number2? ")
packages = csv.reader(open('lol.txt', newline='\n'), delimiter=',')
for PackName,PriceAdultString,PriceChildString in packages:
n += 1
PriceAdult = float(PriceAdultString)
PriceChild = float(PriceChildString)
print("%i. %17s - $%4.2d / $%4.2d" % (n, PackName, PriceAdult, PriceChild))
NameChoice = input("Which name would you like? Choose using a number: ")
The lol.txt used by csv.reader consists of the following:
herp,123,456
derp,321,654
hurr,213,546
Now, I need to be able to use NameChoice to retrieve a row from the file, and use the data within as name, number1, and number2, so for NameChoice == 1, name = herp, number1 = 123 and number 2 = 456, and the numbers must be a floating point number.
I'm having trouble figuring this out, and could use some guidance if that's possible.
Thanks all.
Before it's asked, I realised I forgot to mention: I have googled, and trawled through the Python guides, and my textbooks. I'm not entirely convinced I know what I'm looking for, though.
Run into a new problem:
I need to be able to take CSV text with '\n\n' instead of '\n', so the text is more like the following:
herp,123,456
derp,321,654
hurr,213,546
My (very slightly adjusted) version of the code Li-Aung used:
import csv
with open ("lol.txt",'rt', newline = '\n\n') as f:
csv_r = csv.reader (f)
entries = [ (name, float(p1), float(p2)) for name, p1, p2 in csv_r]
for index, entry in enumerate(entries):
print ("%2i. %-10s %5.2f %5.2f" % (index, entry[0], entry[1], entry[2]))
choice = int(input("Choose a number: "))
print (entries[choice])
Which returns the exception:
Traceback (most recent call last):
File "C:/Python32/eh", line 2, in <module>
with open ("lol.txt",'rt', newline = '\n\n') as f:
ValueError: illegal newline value:
Now, the debug is pretty clear - '\n\n' is not acceptable as a newline specifier, but I was wondering if there is a way around this?
Note: Screwed up the previous edit, the debug from the code with " newline = '\n'" would have been:
Traceback (most recent call last):
File "C:/Python32/eh", line 4, in <module>
entries = [ (name, float(p1), float(p2)) for name, p1, p2 in csv_r]
File "C:/Python32/eh", line 4, in <listcomp>
entries = [ (name, float(p1), float(p2)) for name, p1, p2 in csv_r]
ValueError: need more than 0 values to unpack
Which is because it treated the blank space with 0 values between each useful row as a row, as it was told to do, and there was nothing in there.
#mata has the right of it, but I feel the need to elaborate on their answer more than I can in a comment.
Since you need to refer back to your data instead of just printing it, it makes sense to have it stick around somehow. Once you reach that point, the biggest thing you need to worry about is what kind of data structure to use - if your chosen data structure is a close match to how you want to use the data, the code becomes quite simple.
So, your logic will look like:
Parse the data into some kind of data structure
Walk this data structure to print out the menu
Get the user input, and use it to select the right bit of data
Since the user input is a number representing how far down the file the data is, a list is an obvious choice. If you were using one of the existing fields as a lookup, a dict would serve you better.
If you do:
data = list(csv.reader(open('lol.txt', newline='\n'), delimiter=','))
, you can walk it to print the menu the same way you current use the file, except that the data sticks around, and using the number you get in is directly meaningful.
You might prefer to store the numbers as number types than strings; it would make good sense to, but figuring out how to adjust the code above to achieve it is left as an exercise for the reader. :-)
Store the entire file to a list:
import csv
with open ("lol.txt",'rb') as f:
csv_r = csv.reader (f)
entries = [ (name, float(p1), float(p2)) for name, p1, p2 in csv_r]
for index, entry in enumerate(entries):
print ("%2i. %-10s %5.2f %5.2f" % (index, entry[0], entry[1], entry[2]))
choice = int(raw_input("Choose a number: "))
print (entries[choice])
Output:
0. herp 123.00 456.00
1. derp 321.00 654.00
2. hurr 213.00 546.00
Choose a number: 0
('herp', 123.0, 456.0)
>>>
you could for example store the input in a list instead of just printing it out.
after that it's trivial to get the right tuple from the list and assign it to your variables...
with open ("lol.txt",'rt', newline = '\n\n') as f:
change it to '\n'
with open ("lol.txt",'rt', newline = '\n') as f:
I'm not going to lie. I'm trying to do an assignment and I'm being beaten by it.
I need to have python prompt the user to enter a room number, then lookup that room number in a supplied .txt file which has csv [comma-separated values], and then show multiple results if there are any.
I was able to get python to return the first result ok, but then it stops. I got around the csv thing by using a hash command and .split (I would rather read it as a csv although I couldn't get it to work.) I had to edit the external file so instad of the data being seperated by commas it was seperated by semicolons, which is not ideal as I am not supposed to be messing with the supplied file.
Anyhow...
My external file looks like this:
roombookings.txt
6-3-07;L1;MSW001;1
6-3-07;L2;MSP201;1
6-3-07;L3;WEB201;1
6-3-07;L4;WEB101;1
6-3-07;L5;WEB101;1
7-3-07;L1;MSW001;2
7-3-07;L2;MSP201;2
7-3-07;L3;WEB201;2
7-3-07;L4;WEB101;2
7-3-07;L5;WEB101;2
8-3-07;L1;WEB101;1
8-3-07;L2;MSP201;3
Here's what my code looks like:
roomNumber = (input("Enter the room number: "))
def find_details(id2find):
rb_text = open('roombookings.txt', 'r')
each_line = rb_text.readline()
while each_line != '':
s = {}
(s['Date'], s['Room'], s['Course'], s['Stage']) = each_line.split(";")
if id2find == (s['Room']):
rb_text.close()
return(s)
each_line = rb_text.readline()
rb_text.close()
room = find_details(roomNumber)
if room:
print("Date: " + room['Date'])
print("Room: " + room['Room'])
print("Course: " + room['Course'])
print("Stage: " + room['Stage'])
If i run the program, I get prompted for a room number. If I enter, say, "L1"
I get:
Date: 6-3-07
Room: L1
Course: MSW001
Stage: 1
I should get 3 positive matches. I guess my loop is broken? Please help me save my sanity!
Edit. I've tried the solutions here but keeps either crashing the program (I guess I'm not closing the file properly?) or giving me errors. I've seriously been trying to sort this for 2 days and keep in mind I'm at a VERY basic level. I've read multiple textbooks and done many Google searches but it's all still beyond me, I'm afraid. I appreciate the assistance though.
Your code does "return(s)" the first time the "id2find" argument is exactly equal to the room.
If you want multiple matches, you could create an empty list before entering the loop, append every match to the list WITHOUT returning, return the list, and then use a for-loop to print out each match.
First. For iterating over lines in the file use next:
for line in rb_text:
# do something
Second. Your function returns after first match. How can it match more then one record? Maybe you need something like:
def find_details(id2find):
rb_text = open('roombookings.txt', 'r')
for line in rb_text:
s = {}
(s['Date'], s['Room'], s['Course'], s['Stage']) = line.split(";")
if id2find == (s['Room']):
yield s
rb_text.close()
And then:
for room in find_details(roomNumber):
print("Date: " + room['Date'])
print("Room: " + room['Room'])
print("Course: " + room['Course'])
print("Stage: " + room['Stage'])
And yes, you better use some CSV parser.
Your problem is the return(s) in find_details(). As soon as you have found an entry, you are leaving the function. You do not even close the file then. One solution is to use an empty list at the beginning, e.g results = [], and then append all entries which matches your requirements (results.append(s)).