So I am working on a console based python(python3 actually) program where I use input(">")to get the command from user.
Now I want to implement the "last command" function in my program - when users press the up arrow on the keyboard they can see their last command.
After some research I found I can use curses lib to implement this but there are two problems.
Curses are not available on Windows.
The other parts of my program use print() to do the output. I don't want to rewrite them with curses.
So are there any others ways to implement the "last command" function? Thanks.
In new versions of python exists nice modile readline for handling user input, and rlcompleter for autocomplete purposes. But I think on Windows it will require installation of readline lib anyway.
What you can do, is to apply some sort of shell history functionality: every command issued by the user would be placed in a list, and then you'd implement a special call (command of your console), let's say 'history' that would print out the list for the user in order as it was being filled in, with increasing number to next to every command. Then, another call (again a special command of your console), let's say '!!' (but really coult be anything, like 'repeat') and a number of the command you want to repeat would fetch the command from the list and execute it without retyping: typing '!! 34' would execute again the command number 34 that can be 'something -a very -b long -c with -d very -e large -f number -g of -h arguments -666'.
I am aware its not exactly the same thing that you wanted, but it is very easy to implement quickly, and provides the command repetition functionality you're after, and should be decent replacement until you figure out how to do it the way you want ;)
Related
I am writing a program in Python which must communicate through SSH with a physical target, and send to this targets some commands automatically (it is for testing).
I start by doing this with Paramiko and everything was perfect until I have to send several commands and when for example the second one must be execute in the context of the first (for example the first one makes cd /mytargetRep and the second one is ./executeWhatIWant). I can't use exec_command to do so, because each exec_command starts a new session.
I try to use a channel with invoke_shell(), but I have an other problem with this one: I don't know when command execution is ended by doing this. I can have some very short (in time) command execution, and some other are really more longer so I need to know when the command execution is over.
I know a workaround it to use exec_command with a shell logic operations such as && or using ;. For example exec_command("cd /mytargetRep && ./executeWhatIWant"). But I can't do that, because it must also be possible to execute some commands manually (I have a minimalist terminal where I can send commands), so for example, the user will make cd /mytargetRep then ./executeWhatIWant and not cd /mytargetRep && ./executeWhatIWant.
So my question is: is there a solution by using Paramiko to send several commands in a same SSH session and be able to know the end of the command execution?
Thanks
It seems that you want to implement an interactive shell, yet you need to control individual commands execution. That's not really possible with just SSH interface. "shell" channel in SSH is black box with an input and output. So there's nothing in Paramiko that will help you implementing this.
If you need to find out when a specific command finishes or where an output of a specific command ends, you need to use features of a shell.
You can solve that by inserting a unique separator (string) in between and search for it in the channel output stream. With a common *nix shells something like this works:
channel = ssh.invoke_shell()
channel.send('cd /mytargetRep\n')
channel.send('echo unique-string-separating-output-of-the-commands\n')
channel.send('./executeWhatIWant\n')
Though I do not really think that you need that very often. Most commands that are needed to make a specific commands working, like cd or set, do not really output anything.
So in most cases you can use SSHClient.exec_command and your code will be a way simpler and more reliable:
Execute multiple commands in Paramiko so that commands are affected by their predecessors
Even if you need to use something seemingly complex like su/sudo, it is still better to stick with SSHClient.exec_command:
Executing command using "su -l" in SSH using Python
For a similar question, see:
Combining interactive shell and recv_exit_status method using Paramiko
I have to execute a command and store the output of it in file. The output spans multiple pages and i have to press enter multiple times to see the complete output( similar to that when a man returns multiple pages). I am thinking of using the subprocess module, but how to provide input to the process, when the process prompts.
Disclaimer: I don't know which command you're actually executing so this is just a stab in the dark.
You should not have to provide any input.
Piping the output of the command to cat solves your problem:
less testfile.txt | cat
Also if your goal is to store the output in another file, you can simply to this (this will overwrite):
less testfile.txt > testfilecopy.txt
(and this will append):
less textfile.txt >> logfile.txt
See: https://unix.stackexchange.com/questions/15855/how-to-dump-a-man-page
The best solution is to check if the process does not support a command-line flag to run in "batch mode", disable paging or something similar which will suppress any such "waits". But I guess you have already done that. Given that you have to enter "-help" interactively tells me it's probably no standard unix command which are usually quite easy to run in a sub-process.
Your best bet in that case would be to use expect. There are python bindings available under pexpect.
Expect scripts tend to be fairly ugly, and error-prone. You have to be diligent with error handling. I have only limited practical experience with it as I only modified some of our existing scripts. I have not yet written one myself, but from our existing scripts I know they work, and they work reliably.
What I need to do, is execute a python program/script in conjunction with user presses print, and not let the print job spool before this program quits.
Reason is that the print driver is not open source, and I need to change user settings (in this case a department id and password), that normally is per/user, but as this is a kiosk(different users with the same account) I need to make sure to reset, and prompt user before print jobs is spooled, so that different users won't pick up each others jobs.
I have created a program to handle the settings, I only need a way to start it, and not let the spool job start before the user has finished the program/settings.
I've tried to search/google this but can't really find an answer, do I need to spool the job through a cups filter first or if their is smarter way to handle this?
I found the perfect solution for my problem. tea4cups, it acts as wrapper for cups.
And using a tea4cups prehook solved my issue.
I run into some issues though, so I note them here if someone is coming down the same road.
tea4cups is based on python2 and I have python3 as standard library, this gave some unexpected errors like "wrong key" from cups log.
To solve this I edited "/usr/lib/cups/backend/tea4cups" and changed the environment:
#! /usr/bin/env python
into:
#! /usr/bin/env python2
My prehook needed to start a python program, as the that uses x display, and this was not working out of the box. And also this program needs to be started as the user who actually submit the print job. To get these two things work I had to write the prehook as follows:
prehook_popUp : su $TEAUSERNAME -c "DISPLAY=:0.0 python /usr/share/candepid/PopUp.py"
I want to create a build pipeline, and developers need to set up a few things into a properties file which gets populated using a front end GUI.
I tried running sample CLI interactive script using python that just asked for a name and prints it out afterwards, but Jenkins just waited for ages then hanged. I see that it asked for the input, but there was no way for the user to input the data.
EDIT: Currently running Jenkins as a service..Or is there a good plugin anyone recommends or is it the way I created the python script?
Preference:
I would prefer to use Python because it is a little lightweight, but if people had success with other languages I can comprise.
Using a GUI menu to populate the data, would be cool because I can use option boxes, drop down menus and make it fancy but it isn't a necessity, a CLI is considerably better than our current deployment.
BTW, running all this on Windows 7 laptop running Python 2.7 and Java 1.7
Sorry for the essay! Hopefully people can help me!
Sorry, but Jenkins is not an interactive application. It is designed for automated execution.
The only viable way to get input to a Jenkins job (and everything that is executed from that job) is with the job parameters that are populated before the job is started. Granted, Jenkins GUI for parameter entry is not the greatest, but it does the job. Once the Jenkins job collected the job parameters at the start of the job, it can pass those parameters to anything it executes (Python, shell, whatever) at any time during the job. Two things have to be true for that to happen:
You need to collect all the input data before the job starts
Whatever your job calls (Python, shell, etc) need to be able to receive their input not interactively, but through command line.
How to get input into program
A well designed script should be able to simply accept parameters on the command line:
./goodscript.sh MyName will be the simplest way of doing it, where value MyName will be stored in $1 first parameter of the script. Subsequent command line parameters will be available in variables $2, $3 and so on.
./goodscript.sh -name MyName -age 30 will be a better way of doing it, where the script can take multiple parameters regardless of their order by specifying a parameter name before parameter value. You can read about using getopt for this method of parameter passing
Both examples above assume that the goodscript.sh is written well enough to be able to process those command line parameters. If the script does not explicitly process command line parameters, doing the above will be useless.
You can "pipe" some output to an interactive script that is not designed to handle command line parameters explicitly:
echo MyName | ./interactivescript.sh will pass value MyName to the first interactive prompt that interactivescript.sh provides to the user. Problem with this is that you can only pass a value to the first interactive prompt.
Jenkins job parameters GUI
Like I said above, you can use Jenkins GUI to gather all sorts of job parameters (dropdown lists, checkboxes, text entry). I assume you know how to setup Jenkins job with parameters. If not, in the job configuration click "This build is parameterized" checkbox. If you can't figure out how to set this up, that's a different question and will need to be explained separately.
However, once your Jenkins job collected all the parameters up front, you can reference them in your "execute shell" step. If you are using Windows, you will reference them as %PARAM_NAME%, and for Linux as $PARAM_NAME.
Explain what you need help with: getting your script to accept command line parameters, or passing those command line parameters from jenkins job GUI, and I will expand this answer further
I was working with Python with a Linux terminal screen. When I typed:
help(somefunction)
It printed the appropriate output, but then my screen was stuck, and at the bottom of the terminal was "(end)".
How do I get unstuck? Thanks in advance.
The standard on GNU (or other Unix-like) systems is to use the environment variable PAGER for the command that should receive output for viewing one screenful ("page") at a time.
Mine is set to:
$ echo $PAGER
less
Yours might be set to more, or a different command, or not set at all in which case a system-wide default command will be used.
It sounds like yours is modelled after the more program. The program is showing you page-by-page output, and in this case telling you you're at the end.
Most of them (basically, any pager more modern than more) allow you to go forward and backward in the output by using the cursor control keys (arrows and PgUp/PgDown), and many other operations besides.
Since you can do all these things wherever you are in the output, the program needs an explicit command from you to know that you're done navigating the output. In all likelihood that command is the keypress q.
For more information on how to drive your pager, e.g. less, read its manpage with the command man less (which, of course, will show pages of output using the pager program :-)
That program uses your pager, which is by default more. You can exit just by pressing q.