When running a shell or most programs in a shell anything you type is echo'd back to the user's terminal by the kernel's tty subsystem. There's other special handling, too, for erase characters, Ctrl+R, Ctrl+Z, and so on.
Certain programs, (editors in particular) that run from a command line don't need or want this. For this reason they signal the kernel with an IOCTL call against the tty (terminal) device that they don't want this behaviour. They don't want special characters to do special things, either. Instead they ask the kernel for a "raw" mode. In particular, editor's like vim turn off various "echo settings". All this applies to real tty terminals on a computer's serial lines, or the virtual terminals at Alt+Ctrl+F4, or the really virtual terminals you get when you run something like gnome-terminal under a GUI.
Such programs are supposed to reset any modes they change on the virtual tty they are using before they quit, either by entering a quit editor command or by taking a signal (from Ctrl+C) for example.
If they fail to do this properly the tty is left in the funny state you have discovered. Since programs can fail to reset the terminal, the reset
command was written to allow the user to recover.
I assume the interrupt is messing with the python software you are running. I'd guess that that program isn't getting a chance to reset the terminal, or is simply failing to do so.
In the vim case, when I run your example I get the same behaviour you describe. I also see a message "Vim: Warning: Input is not from a terminal" (It goes away when you reset). This is because vim isn't started normally from the shell. Instead the 'grep
' and 'xargs
' commands have been using the standard input, normally occupied by the tty, for purposes of passing the file names from grep
tto xargs
.
In your posted output from stty -a
we can see "-echo", also confirming that this is the problem. If you were to kill vim in such a way that it couldn't handle the signal gracefully you would probably see the same problem.
The problem is described elsewhere at https://stackoverflow.com/questions/3852616/xargs-with-command-that-open-editor-leaves-shell-in-weird-state.
A solution for the vim case is avoid xargs and use instead:
vim $(grep foo * -l)
Here the list of files is constructed by the shell, as it had been by xargs, but the shell is calling vim, which is directly connected to the tty. There is warning message sent to the error output file, and vim sets and resets the tty settings correctly.
An alternative to reset
that doesn't clear the screen is stty sane
.
More references here, and another interesting one here. Another interesting solution is given in an answer to https://stackoverflow.com/questions/8228831/why-does-locate-filename-xargs-vim-cause-strange-terminal-behaviour.
You should be able to do what you have in mind by using command grouping, which allows you to execute commands together, in this case, whether they succeed or not, i.e. in the form { cmd; cmd; }
. More information on command grouping and the use of && and || logical operators is available at the Bash wiki and in the Bash reference manual.
I thought initially the form your command-line could take would be:
{ cmd1; cmd2; cmd3; }; sleep 1; { cmd4; cmd5;}
The sleep command just gives a pause and can be removed.
However, you say you want an extra return, or confirmation for the last two commands, and so to achieve that you need to interrupt the command flow in the example above- sleep merely pauses, but regardless the last two commands always execute.
To really halt the command chain, you could use read -p.....
which requires user intervention to continue. Here is what you could do:
1) Execute the first three commands, then give the user the opportunity or not to execute the last ones. You could see if the oneliner I have written below is suitable:
Note: Please substitute the id command for your own commands.
id; id; id; read -p "Execute final two commands? (Y/N) " ans; if [[ $ans =~ Y|y ]]; then id; id; else echo "Finished"; fi
Now the first three commands execute and then you need to press y and return for the last two to execute, but all the commands are on the same line. This is about as much as I can contrive really, as I am not quite sure what you want.
Best Answer
Simple really - you need to separate the commands. For instance this:
will update the package lists, and then the packages. Another possibility is this (probably better, as the && will only allow the
upgrade
command to run if theupdate
exits successfully):This should run the commands for updating the list of packages and then the package themselves. This would need to be saved into a text file (e.g.
updatescript
in the home directory). You can then make it executable by running:or by right clicking on the file and making it executable in its properties:
and run it with this in terminal:
Note(s):
There is an option (
-y
) available that can be used with theupgrade
command so it does not prompt before upgrading the packages. It is a good idea to check whatapt-get
is doing before it upgrades the packages, as it may/will do something stupid or something you don't want it do. More info on options like this can be found by runningman apt-get
.This also means it is more ideal to use the terminal to run the script, as you can check what it is updating, and then run it. If you want a GUI way to run the updates, use the software-center as that it is what it is for.