I found this code snippet online for a python terminal emulator, I thought it looked cool so I went ahead and attempted to use it. I noticed that I'm not able to use the "cd" command, I'm stuck in the directory I ran the file in. Why is this? What's going on? And how can I modify this code to make it run like a perfect native terminal? I'm still very new to programming and have only played with the subprocess module once in my life. Please help!
import subprocess
import re
while True:
# prevents lots of python error output
try:
s = raw_input('> ')
except:
break
# check if you should exit
if s.strip().lower() == 'exit':
break
# try to run command
try:
cmd = subprocess.Popen(re.split(r'\s+', s), stdout=subprocess.PIPE)
cmd_out = cmd.stdout.read()
# Process output
print cmd_out
except OSError:
print 'Invalid command'
When you open a new process you change the current directory for the new process and not for the calling process. You should use os.chdir instead to change the directory of your program. So you need to parse the command line and check if the command is cd and then decide not to call Popen but os.chdir instead.
Related
In a program I am writing in python I need to completely restart the program if a variable becomes true, looking for a while I found this command:
while True:
if reboot == True:
os.execv(sys.argv[0], sys.argv)
When executed it returns the error [Errno 8] Exec format error. I searched for further documentation on os.execv, but didn't find anything relevant, so my question is if anyone knows what I did wrong or knows a better way to restart a script (by restarting I mean completely re-running the script, as if it were been opened for the first time, so with all unassigned variables and no thread running).
There are multiple ways to achieve the same thing. Start by modifying the program to exit whenever the flag turns True. Then there are various options, each one with its advantages and disadvantages.
Wrap it using a bash script.
The script should handle exits and restart your program. A really basic version could be:
#!/bin/bash
while :
do
python program.py
sleep 1
done
Start the program as a sub-process of another program.
Start by wrapping your program's code to a function. Then your __main__ could look like this:
def program():
### Here is the code of your program
...
while True:
from multiprocessing import Process
process = Process(target=program)
process.start()
process.join()
print("Restarting...")
This code is relatively basic, and it requires error handling to be implemented.
Use a process manager
There are a lot of tools available that can monitor the process, run multiple processes in parallel and automatically restart stopped processes. It's worth having a look at PM2 or similar.
IMHO the third option (process manager) looks like the safest approach. The other approaches will have edge cases and require implementation from your side to handle edge cases.
This has worked for me. Please add the shebang at the top of your code and os.execv() as shown below
#!/usr/bin/env python3
import os
import sys
if __name__ == '__main__':
while True:
reboot = input('Enter:')
if reboot == '1':
sys.stdout.flush()
os.execv(sys.executable, [sys.executable, __file__] + [sys.argv[0]])
else:
print('OLD')
I got the same "Exec Format Error", and I believe it is basically the same error you get when you simply type a python script name at the command prompt and expect it to execute. On linux it won't work because a path is required, and the execv method is basically encountering the same error.
You could add the pathname of your python compiler, and that error goes away, except that the name of your script then becomes a parameter and must be added to the argv list. To avoid that, make your script independently executable by adding "#!/usr/bin/python3" to the top of the script AND chmod 755.
This works for me:
#!/usr/bin/python3
# this script is called foo.py
import os
import sys
import time
if (len(sys.argv) >= 2):
Arg1 = int(sys.argv[1])
else:
sys.argv.append(None)
Arg1 = 1
print(f"Arg1: {Arg1}")
sys.argv[1] = str(Arg1 + 1)
time.sleep(3)
os.execv("./foo.py", sys.argv)
Output:
Arg1: 1
Arg1: 2
Arg1: 3
.
.
.
CMD writes this when I run command "vsc" which open VSCode
This is the function i made to open VSCode
def openVSC():
subprocess.call(["C:\\Program Files\\Microsoft VS Code\\Code.exe"])
And this is the code that calls the function "openVSC()"
while True:
command_input = input(prompt).lower()
if command_input == "open spotify":
print("Opening Spotify...")
openSpotify()
print()
elif command_input == "www":
print("Opening Google Chrome...")
openChrome()
print()
elif command_input == "vsc":
print("Opening VSCode...")
openVSC()
print()
elif command_input == "quit":
break
else:
pass
Also when I close the cmd VSCode also closes so I was thinking that the CMD was running VSCode on his own... Nothing seems to work and i tried about everything.
Your question is very vague, more information would be appreciated. Assuming you issue is that you are only getting STDOUT from the vscode call, thats because you are using call(), which waits for the process to complete before returning control to your program. Use something like this to make your call, and you can set where STDOUT points to as to read output whilst using the program being called by your script.
from subprocess import Popen, STDOUT
import os
Popen(['vscode'], stdout=os.open(os.devnull, os.O_RDWR), stderr=STDOUT)
This will open the process to run as a child and your program will wait for the child to terminate at this point. Read more into subprocess and this should all make more sense. hope this helps!
I am running this python code from the command line:
# run on command line as: python firstscript.py
import sys, subprocess
pid = subprocess.Popen([sys.executable, 'secondscript.py']).pid
sys.exit()
Unfortunately I can't get it to exit all the way to the command line. If I hit the enter key (on OSX) it will finally exit. Is there a way to force the script to exit all the way to the command line without lingering in this weird limbo state? Also, I don't want to redirect stdout or stderr anywhere else because if I do, I lose the ability in secondscript.py to log output to a log file.
Thanks for the help.
The changes below worked for me:
# run on command line as: python firstscript.py
import sys, subprocess
process = subprocess.Popen([sys.executable, 'secondscript.py'])
output = process.communicate()[0]
You seem to be asking if there is a better way to do this. Check out check_output. I have always found it much more convenient and fool proof compared to the lower level stuff in subprocess.
This is a weird one that's so general I can't to properly narrow the search terms to find an answer.
My python script has a raw_input to prompt the user for values. But, when I try to run the script and funnel it into a file, it crashes.
Something like "script.py > save.txt"
wont work. It doesn't even properly prompt me at the command line for my input. There doesn't seem to be anything indicating why this doesn't work as intuitively as it should.
raw_output prints its prompt to stdout, which you are redirecting to a file. So your prompt will end up in the file and the program does not appear to show a prompt. One solution is to output your prompt to stderr.
import sys
sys.stderr.write('prompt> ')
value = raw_input()
print('value was: ', value)
You could also avoid using both pipes and interactive input with the same script. Either take input from command line flags using argparse and use pipes, or create an interactive program that saves output to a file itself.
Depending on your program's logic, you can also check whether stdout is connected to a live console or not:
is_tty = os.isatty(sys.stdout.fileno())
Dolda2000 also has a good point about writing to /dev/tty, which will write to the controlling terminal of the script being run even if both stdin and stderr are redirected. The deal there, though, is that you can't use it if you're not running in a terminal.
import errno
try:
with open('/dev/tty', 'w') as tty:
tty.write('prompt> ')
except IOError as exc:
if exc.errno == errno.ENXIO:
pass # no /dev/tty available
else:
pass # something else went wrong
I know that i can just add the location and create a bash script. but I want to run a program (c or Java code). I tried using 'call' and 'execfile' but without success. please help me. I also want to print 'success' if it opens.
from subprocess import Popen,PIPE
proc = Popen(["/path/to/java_exe","/path/to/a.java"],stderr=PIPE,stdout=PIPE)
stderr,stderr = proc.comunicate()
if proc.returncode == 0:
print "SUCCESS?"
maybe ... its not really very clear what you are trying to do.