I am starting to learn python and I decided to start with what I though was a simple script but I guess not. All I want to do is return what current network location I am using on my mac. Every time I run it, it gives me back the correct location but then when I try to change it, nothing happens. I don't know what I am doing wrong so here is my code. I really hope some one can help me. This script is unique to MACS btw. I know that the "scselect" is built in but I wanted to see if it could be done with Python. The code below is rough I know but as I learn I will make it better. I am using Python 2.7.
import subprocess
loc = "scselect"
srn = "scselect SRN"
home = "scselect HOME"
a = subprocess.check_output(loc, shell=True)
print "\n##### NETWORK SELECTION #####"
print "\nYour current location is set to \n\n%s" % a
choice = raw_input("Please select what location you want to change to: ")
b = subprocess.Popen(srn, shell=True, stdout=subprocess.PIPE)
c = subprocess.Popen(home, shell=True, stdout=subprocess.PIPE)
choice = int(choice)
if choice == 1:
print "\nSwitching to HOME...\n"
c
elif choice == 2:
print "\nSwitching to SRN...\n"
b
else:
print "\nShutting down...\n"
You run both scselect commands first, then only display the output of one of the commands.
By the time you come to if choice == 1, etc. both b and c have already been set and have captured the output of the commands. Both scselect SRN and scselect HOME have been run, with the last one undoing anything the first command achieved.
Move the subprocess calls into the if statements:
if choice == 1:
print "\nSwitching to HOME...\n"
output = subprocess.Popen(home, shell=True, stdout=subprocess.PIPE)
print output
Related
I'm working on a piece of code in Python 3 that acts as an interface for various dead by daylight cheats. I'm using a very basic setup, just input() and os.system() to find and open specific files. It works fine, but there's one small issue.
The interface uses cmd prompt, and I have it set up so that entering numbers 1-4 will open programs and executables used to modify the game. However, some of the programs are required to stay open while others run. For example, the BVHR Session Grabber must be running along with the SaveInjector Interface, because the SaveInjector needs to receive a certain code from the Grabber.
There's a problem here, the code is set up in such a way that you can only run one file at a time. I'm not sure what exactly causes this, but I'll try to explain what happens. When entering the number 1, for example, into the cmd prompt window, it opens the BHVR Session Grabber (as intended). After that, the interface becomes unusable until I close the BHVR Session Grabber. I can't type anything into it while it's active, so I can't open multiple programs at once.
Not entirely sure if this is intended or not, but I'm hoping it's avoidable. If anyone has any knowledge on the issue let me know how to find a way around this in the comments please.
import os.path
def interface():
os.system('cls' if os.name == 'nt' else 'clear')
print("""
\n\nSelect a cheat below:
\n
\n1: BHVR Session Grabber
\n2: SaveInjector Interface
\n3: Rank / Shards Editor
\n4: Exit\n
""")
def checker():
interface()
lst = ['1','2','3','4']
good_input = input(">")
global user_input
user_input = None
while not user_input:
if good_input in lst:
user_input = good_input
else:
print("Enter a valid integer.")
good_input = input(">")
checker()
cwd = os.getcwd()
def selection():
if user_input == '1':
f = (os.path.join(cwd, 'Programs', 'BHVRSession', 'CookieFinder.exe'));
os.system(f)
checker()
selection()
elif user_input == '2':
os.system('cmd /k "cd Programs & cd Injector & SI.exe & cd.. & cd.. & Ultimate.py"')
elif user_input == '3':
f = (os.path.join(cwd, 'Programs', 'RankShards', 'Sender.exe'));
os.system(f)
checker()
selection()
elif user_input == '4':
os.system('cmd /k "taskkill/im py.exe"')
selection()
The problem here is that os.system() is blocking. This means that it will only return and continue executing your Python code after the program it runs finishes. Instead, you should look at the subprocess package to learn how to fork a new process that can run in parallel with your Python program.
office_list = []
print("Type in your office supplies.\nEnter 'DONE' to print out your list.\n--------------------\n")
while True:
list = input("> ")
if list == 'DONE':
break
office_list.append(list)
print("Here is your list\n--------------------\n")
for ls in office_list:
print(ls)
I've been trying to find this online but seem to have trouble trying to find the correct vocabulary I believe.
What I am trying to make the program do is clear what I have written to make the list and then print the list. What happens in the program right now is it will have the words I typed on top of the list and print when I enter the word 'DONE'.
You can use the os module. Under *nix, you can use os.system('clear') or os.system('cls') under Windows.
Using the os module, you can run shell commands. To clear the console on Linux/macOS you can use the clear command, on Windows there's cls:
import os
import sys
def clear():
if sys.platform == 'windows':
os.system('cls')
else:
os.system('clear')
Just print enough newline characters like this:
print('\n' * 50)
It doesn't hurt to print out too many lines for a console application as this will all happen in a split second. This method is cross-platform and should work in nearly any environment.
The OS-level answers actually do the same thing, but the OS knows exactly how many lines to print. If you don't care about hiding the precise number of lines that are shown on the screen, just print out enough (within reason) to clear the console.
The best way to explain my question is with the help of an example.
Consider a Python Script that asks a question and gives an answer depending on the question.
QandA.py
import os,sys,re
ans = input('How you doin\' \(Say Yes\/No\)')
if (ans == "Yes"):
print("Nice to hear")
elif (ans == "No") :
print("Oh Too Bad")
The above Script would normally prompt the User for an Input, BUT I'd also like it to be called by a Batch Script which will provide the input to the called Python Script.
I'll hardcode these inputs in the Batch File itself (as seen below).
call.bat
set ans="Yes"
D:
cd "Automate Answers"
python "QandA.py"
Is there any way to achieve this (make the Python Script aware of ans) without modifying the Python Script itself to handle optional command line arguments ?
I'd prefer the Batch Script to run as if it were the user giving inputs to the script from an array of variables.
Variables set in .bat, .cmd, should show up as environment variables.
Python can read environment variables passed in via the os.environ
import os
print(os.environ['ans'])
thus you could write:
import os
ans = os.environ.get('ans')
if ans is None: # it was not set, so ask user
ans = input("How you doin' (Say Yes/No)")
if ans == "Yes":
print("Nice to hear")
elif ans == "No":
print("Oh Too Bad")
or even do a function:
def env_or_input(var_name, prompt):
val = os.environ.get(var_name)
if val is None: # it was not set, so ask user
val = input(prompt)
return val
...
ans = env_or_input("ans", "How you doin' (Say Yes/No)")
if ans == "Yes":
print("Nice to hear")
elif ans == "No":
print("Oh Too Bad")
I suppose that echo 'Yes' | python QandA.py would work. You can add several answers in a fixed sequence, separated by newlines:
cat <<EOF | python QandA.py
Yes
No
Why are you asking?
EOF
For longer scenarios when you e.g. have to react to changing prompts, you can use expect.
Piping in a single answer is trivial:
set ans="Yes"
cd /d "D:Automate Answers"
echo %ans%|python "QandA.py"
But piping in multiple answers is tricky. The following is broken because the batch parser inserts an extra space before each & and )
(echo val1&echo val2&echo val3)|python "script.py"
The easiest way to provide multiple answers without extra space is to delay the appearance of the & so the initial parsing pass that prepares the pipe sees only a single ECHO on the left side
set "+=&"
echo val1%%+%%echo val2%%+%%echo val3|python "script.py"
I'm trying to implement a small script to manage a localhost with an FTP connection in Python from the command line and using the appropriate "ftplib" module. I would like to create a sort of raw input for the user but with some commands already setup.
I try to explain better:
Once I have created the FTP connection and login connection been successfully completed through username and password, i would show a sort of "bash shell" with the possibility to use the most famous UNIX commands ( for example cd and ls respectively to move in a directory and show file/folders in the current path ).
For example i could do this:
> cd "path inside localhost"
thus showing directories or:
> ls
to show all files and directories in that particular path. I've no idea how to implement this so i ask you some advices.
I thank you so much in advance for the help.
It sounds like the command line interface is that part that you are asking about. One good way to map user inputs to commands is to use a dictionary and the fact that in python you can run a reference to a function by putting () after it's names. Here's a quick example showing you what I mean
def firstThing(): # this could be your 'cd' task
print 'ran first task'
def secondThing(): # another task you would want to run
print 'ran second task'
def showCommands(): # a task to show available commands
print functionDict.keys()
# a dictionary mapping commands to functions (you could do the same with classes)
functionDict = {'f1': firstThing, 'f2': secondThing, 'help': showCommands}
# the actual function that gets the input
def main():
cont = True
while(cont):
selection = raw_input('enter your selection ')
if selection == 'q': # quick and dirty way to give the user a way out
cont = False
elif selection in functionDict.keys():
functionDict[selection]()
else:
print 'my friend, you do not know me. enter help to see VALID commands'
if __name__ == '__main__':
main()
I'd like to get input on the terminal and give only a few seconds to respond. When the timeout is reached I'd like to read whatever has been typed in an accept that as the given input. Optionally I'd like the user to be able to press "enter" to submit their answer early.
I have the code below which works ok, but requires the user to press "enter" to submit. It has a bug: Entering text and then waiting for the timeout keeps the text in the "buffer". Then when you get prompted again you enter different text, press enter and then both strings are printed (see output). When the timeout is reached I'd like to accept whatever has been typed as "the answer." I'd like the user to still be able to submit an answer faster by pressing "enter".
Is there a way to achieve the desired behavior?
Note: I'm using Mac OS X
import sys
from select import select
def getResponse(timeout):
print "Enter something:"
rlist, wlist, xlist = select([sys.stdin], [], [], timeout)
if rlist:
result = sys.stdin.readline()
return result
else:
return ''
while True:
response = getResponse(3)
print "Your input is:", response
Output:
Enter something:
pythonYour input is:
Enter something:
dangit
Your input is: pythondangit
You want to read user input from terminal in a non-blocking manner and also be able to timeout the reading and then get what has been written without needing to press enter. That is problematic at least, there isn't going to be an easy answer for that. As a starting point, you might consider using the following ncurses code. The user better not need to erase his input! The code can be adjusted to handle character deletion, and many other "fancy" features, in the end you might end with a mini-terminal.
What you are asking for is typically done using event loops, including the reading part (where raw_input is a bad choice). A GUI toolkit could solve that more easily, and more robustly (but of course it has some thousands lines behind it).
import time
import curses
ENTER_KEY = (curses.KEY_ENTER, ord('\n'), ord('\r'))
def run(win, timeout=3): # timeout in seconds
curses.echo()
win.timeout(0) # Non-block read.
line = 0
while True:
win.addstr(line, 0, "Enter something: ")
s = []
start = time.time()
run = True
while run:
c = win.getch()
time_taken = time.time() - start
if c < 0:
pass
elif c in ENTER_KEY:
break
else:
s.append(chr(c))
if time_taken >= timeout:
# Out of time.
s.append(-1)
run = False
if len(s) == 0:
break
if s[-1] == -1:
s.pop()
answer = ''.join(s)
win.addstr(line + 1, 0, "Your input was: %s" % answer)
line += 2
curses.wrapper(run)
To end gracefully press enter without typing anything. If the time runs out, it continues asking for input. I didn't test this code at all, I'm just aware of its many limitations.
This is not normal console behavior, but here is a post that discusses a few options:
Keyboard input with timeout in Python