Depending on how the terminal is configured, typing Alt+Key is like typing the Esc and Key keys in sequence, so it sends the ESC character (aka \e
or ^[
or \033
) followed by the character or sequence of characters sent upon pressing that Key.
Upon pressing Up, most terminal emulators send either the three characters \033[A
or \033OA
depending on whether they're in application keypad mode or not.
The first one does correspond to the escape sequence which when output to the terminal, move the cursor up. If you do:
printf '\nfoo\033[Abar\n\n'
You'll see bar
written after foo
one row up. If you do:
stty -echoctl; tput rmkx; read foo
You'll see that the arrow keys do move the cursor around.
When an application like zsh
or vi
reads that sequence of characters from the terminal, it interprets it as the "Up" action, because it knows from the terminfo database (kcuu1
capability) that it is the escape sequence sent upon pressing Up.
Now, for Alt-Up, some terminals like rxvt
and its derivatives like eterm
send \033
followed by the escape sequence for Up (that is \033\033[A
or \033\033OA
), while some others like xterm
or gnome-terminal
have separate escape sequences for those types of keys when used with the combination keys like Alt, Shift, Ctrl.
Those will typically send \033[1;3A
upon Alt-Up.
When sent to the terminal, that sequence will also move the cursor up (the second parameter (3) is ignored). There's no corresponding keypad key, so it's the same sequence sent upon Alt-Up in or out of application keypad mode.
Now whether it's \033\033[A
or \033[1;3A
, many applications don't know what those sequences are for. The terminfo database won't help them, because there's no such capability that defines what characters those key combinations send.
They will try their best to interpret that sequence. bash
for instance will interpret \033[1;3
as an escape sequence, doesn't know anything about it, so does nothing, followed by A
. zsh
, will stop reading as soon as it finds out there's no known matching character sequence. There's no escape sequence that it knows that starts with \033[1
so it will skip that, and read the rest: ;3A
and insert that in the line editor.
Many applications like vi
, zsh
or readline
based ones like gdb
or bash
(though beware bash
uses a modified version of readline
) allow you to add bindings for any sequence of characters.
For instance, in zsh
, you may want to bind Alt-Up, Alt-Down like:
bindkey '\e[1;3A' history-beginning-search-backward
bindkey '\e[1;3B' history-beginning-search-forward
Those are to search the history backward and forward for command lines that start like the current one up to the current position of the cursor which is quite handy to recall previous commands.
The difference is only in the wording of the padding behavior in the V4-V5 manual - but the behavior is the same throughout. As it stands the results of the V5 implementation is
identical to that of the System V one, which is itself identical to the GNU tr
behavior with the --truncate-set1
option. Furthermore, "truncating set1 to the lenght of set2" gives the same result as "padding string2 with corresponding characters from string1". It means the same thing in practice. Let's demonstrate this.
First, you need not be a developer to try to compile this. Compare the source code with the almost identical PWB/Unix version. You will see the only difference being reliance on the "modern" stdio.h assets basically, so I've stripped the source of its references to inbuf
, fout
, dup
and flush
and replaced it with what PWB/Unix does - but this in no way should alter the behavior as the algorithms remain untouched. I've annotated the trivial changes I've made from the original:
#include <stdio.h> <------ added
int dflag = 0; <------ added "=" sign to those
int sflag = 0;
int cflag = 0;
int save = 0;
char code[256];
char squeez[256];
char vect[256];
struct string { int last, max, rep; char *p; } string1, string2;
FILE *input; <------ part of the stdio framework I guess;
main(argc,argv)
char **argv;
{
int i, j;
int c, d;
char *compl;
string1.last = string2.last = 0;
string1.max = string2.max = 0;
string1.rep = string2.rep = 0;
string1.p = string2.p = "";
if(--argc>0) {
argv++;
if(*argv[0]=='-'&&argv[0][1]!=0) {
while(*++argv[0])
switch(*argv[0]) {
case 'c':
cflag++;
continue;
case 'd':
dflag++;
continue;
case 's':
sflag++;
continue;
}
argc--;
argv++;
}
}
if(argc>0) string1.p = argv[0];
if(argc>1) string2.p = argv[1];
for(i=0; i<256; i++)
code[i] = vect[i] = 0;
if(cflag) {
while(c = next(&string1))
vect[c&0377] = 1;
j = 0;
for(i=1; i<256; i++)
if(vect[i]==0) vect[j++] = i;
vect[j] = 0;
compl = vect;
}
for(i=0; i<256; i++)
squeez[i] = 0;
for(;;){
if(cflag) c = *compl++;
else c = next(&string1);
if(c==0) break;
d = next(&string2);
if(d==0) d = c;
code[c&0377] = d;
squeez[d&0377] = 1;
}
while(d = next(&string2))
squeez[d&0377] = 1;
squeez[0] = 1;
for(i=0;i<256;i++) {
if(code[i]==0) code[i] = i;
else if(dflag) code[i] = 0;
}
input = stdin; <------ again stdio
while((c=getc(input)) != EOF ) { <------
if(c == 0) continue;
if(c = code[c&0377]&0377)
if(!sflag || c!=save || !squeez[c&0377])
putchar(save = c);
}
}
next(s)
struct string *s;
{
int a, b, c, n;
int base;
if(--s->rep > 0) return(s->last);
if(s->last < s->max) return(++s->last);
if(*s->p=='[') {
nextc(s);
s->last = a = nextc(s);
s->max = 0;
switch(nextc(s)) {
case '-':
b = nextc(s);
if(b<a || *s->p++!=']')
goto error;
s->max = b;
return(a);
case '*':
base = (*s->p=='0')?8:10;
n = 0;
while((c = *s->p)>='0' && c<'0'+base) {
n = base*n + c - '0';
s->p++;
}
if(*s->p++!=']') goto error;
if(n==0) n = 1000;
s->rep = n;
return(a);
default:
error:
write(1,"Bad string\n",11);
exit(0); <------original was exit();
}
}
return(nextc(s));
}
nextc(s)
struct string *s;
{
int c, i, n;
c = *s->p++;
if(c=='\\') {
i = n = 0;
while(i<3 && (c = *s->p)>='0' && c<='7') {
n = n*8 + c - '0';
i++;
s->p++;
}
if(i>0) c = n;
else c = *s->p++;
}
if(c==0) *--s->p = 0;
return(c&0377);
}
So cc tr.c
compiles:
tr.c: In function ‘next’:
tr.c:118:4: warning: incompatible implicit declaration of built-in function ‘exit’
[enabled by default]
exit(0);
^
But a.out is there and works, so let's now compare the padding behavior of the two programs we have:
GNU tr
#tr 0123456789 d
0123456789 input
dddddddddd output <----- BSD classic behavior
#tr 0123456789 d123456789 <----- padding set2 with set1 explicitly
0123456789 i
d123456789 o
01234567890123456789 i
d123456789d123456789 o
#tr -t 0123456789 d <----- --truncate-set1 i.e. System V behavior
0123456789 i
d123456789 o <----- concretely, this is what is meant by a result
0012 i where set2 was padded with set1
dd12 o
#tr -t 0123456789 d123456789 <----- padding set2 with set1 explicitly
0123456789 i
d123456789 o <----- note this is identical to the last results
Unix V5 tr + stdio mod
#./a.out 0123456789 d <----- our compiled version with the classic example
0123456789 i
d123456789 o
./a.out 0123456789 d123456789 <----- padding set2 with set1 explicitly
0123456789 i
d123456789 o
So our V5 version behaves exactly like the System V version in that respect. Furthermore explicitly padding set2 with set1 yields the same result for all implementations because it insures that set1 and set2 have the same number of elements (and it's when you don't have this that results vary historically).
Finally, explicitly padding or having tr
pad set2 with set1
as described in the original V4-V5 manuals means the same thing as truncating set1 to the length of set2
insofar as results are concerned - it IS the classic System V implementation for padding and yields the same results. V5 tr
is not a different implementation, despite the difference in the man pages.
Best Answer
Terminal line control can be queried and/or set by
stty
. To see the current settings, usestty -a
. The manpages provide details.For example, from
stty -a
you might find this kill-line control:The caret means hold the control key (Ctrl) and then type the character shown (
U
). To change the line-kill sequence, you could do:NOTE: The backslash is an escape to signify that the character following is to be interpreted literally by the shell.
Having changed your line-kill to this, (a literal @), you can now obliterate a line that looks like:
NOTE: In the above, scenario, when you type ddtae, when you type the character @, the entire line will be erased.
One way to restore the default settings (and this is very useful when you have inadvertently altered settings) is to simply do:
Yet another use of
stty
is to control character echo-back. For instance, a simple way to hide a user's password as (s)he types it is to do: