I wanted to configure the keyboard in zsh and bash on z/OS so the delete key (top right of the keyboard) deleted the current character. (Backspace deletes the previous character) I could not find any good documentation on how to do it.
I found some bash for Linux documentation and have based this blog post on that. I’ve given the command I used, then sections on the background of how it works.
Note the binding of key to action depends on the shell. The shells zsf and bash support binding. shell does/may not.
Having written the original blog post, I found some additional useful information which will make the document clearer.
How to set the delete key to delete
With my Bash shell, I initially had to do it in stages:
- Type bind “ that’s bind space double quote
- Control+V, delete key to insert the value of the key. This made it bind “^[[3~
- Type “:delete-char with no space after the :
- It now looks like bind “^[[3~”:delete-char
- Press enter
- The delete key should delete the character under the cursor
The command bind -p |grep delete gave
"\C-h": backward-delete-char
"\C-?": backward-delete-char
"\C-d": delete-char
"\M-[3~": delete-char
"\\": delete-char
# delete-char-o
Which shows that Ctrl+d and \\ also deletes the current character.
In a shell (in ASCII) this is (in ISPF edit with hex on)
bind '" ∇3~":delete-char'
6666222153723666676266672222
29E4072BB3E2A45C545D38127000
Where the incantation is x1b5b337e.
What does the mapping mean?
It took me many hours of looking for a good description of what the key mapping is.
The Wikipedia page ANSI escape codes, was very helpful and clear.
- You can press the “a” key – and “a” is displayed in the command window.
- You can press shift “a” – and “A” is displayed in the command window
- You can press Control (Ctrl) “a” – and this may do something
- You can press Meta “the Windows” key “a” and this may do something
- You can press Alt + “a” and it may do something.
- You can press combinations of those keys, such as Ctrl+shift + “a” and this may do something.
The operating system may intercept the key and not pass it to the window. For example on my Linux, Ctrl+Alt+Delete is logout.
In the command window the shell code will intercept a key press combination and take an action, for example move the cursor left, clear the screen, delete word, or just the the character.
You can change the mapping using the bind or bindkeys command for bash and zsf shells.
You can find the code for a key combination by using ctrl+v. For example with the left cursor key
Ctrl+v, < gives ^[[D
How to decode ^[[D ?
There are several formats.
- <esc>[ number(;modifier)~
- <esc>[ letters
The string starts with an escape sequence. ^[ This can be written as \e ,\033, 0x1b, or ^[. Where \0 is octal 33, which is hex 1B, (and decimal 27). When specifying a key sequence any of the values can be used. I mentioned above the incantation x1b5b337e.
Because there is no trailing ~ we need to lookup the “[D” in the Wikipedia page section xterm sequences. This has
<esc>[D - Left
So for ^[[D we have <esc>, Left key pressed
For ^[[3;5~ we have
- ^[ is escape
- [3 isDelete key
- ; is a modifier
- 5 is Control + shift
- ~ end of escape
so the key presses was Control + Delete key (top right on my keyboard). Shift seems to be ignored!
Another popular key is ^M which is Carriage Return – (and process any data on the line) and move the cursor to column 0.
\C is the Ctrl key, \M is the meta key. For keyboards without the Meta key this is displayed as Escape \e.
Keys like \M-OD comes from
Keypad mode
"\M-OD":backward-char
"\M-OC":forward-char
"\M-OA":previous-history
"\M-OB":next-history
This information is not well documented.
What is key mapping
On Linux Ubuntu the control-right arrow combination moves the cursor right one word. The control-left arrow moves the cursor left one word. Control-L clears the screen, but leaves the command line intact.
- You can list the possible actions
- Get a list of functions and what keys use them
- Get a list of keys and their functions in bind format
You can list the possible actions
bind - l
This gave
...
arrow-key-prefix
backward-byte
backward-char
backward-delete-char
backward-kill-line
backward-kill-word
...
Get a list of functions and what keys use them
With upper case -P
bind -P |grep backward
This gave
backward-byte is not bound to any keys
backward-char can be found on "\C-b", "\eOD", "\e[D".
backward-delete-char can be found on "\C-h", "\C-?".
Where does \eOD come from ? See here.
Get a list of keys and their functions in bind format
with lower case -p
bind -p |grep backward
gave
"\eOD": backward-char
"\e[D": backward-char
"\C-h": backward-delete-char
"\C-?": backward-delete-char
...
where
- Control-h moves the cursor left one character and deletes the character
- \e is the escape key. The alt key is usually mapped to the escape key by terminal emulators.
This output is slightly untrue. If there is no blank after the : you can use bind….
If you have a blank after the : you need to enclose it in single quotes.
bind ‘”\C-h”: backward-delete-char’
to set the key.
What is the code for a key press combination?
The Linux command Ctrl-V (verbatim insert) followed by a key, gives the mapping for that key.
Ctrl+V LeftArrow
^[[D
Ctrl+V Ctrl+Leftarrrow
^[[1;5D
Where ^[ means the escape key and [D is OD.
^[[3~ is escape Delete key.
Verbatim insert gives the code of the key which was pressed. This works on z/OS if you have the Bash or zsf shell installed.
What keys are mapped?
In the zsh shell you can issue
bindkey -L
(With bash you can use the bind command).
This gives output like
bindkey "^E" end-of-line
...
bindkey "^L" clear-screen
Where ^ is the ctrl key.
If you type (on Linux) man bash , and locate Readline Command Names if lists the function names and what they mean.
The bash command bind -l lists all of the functions
$ bind -q backward-char
backward-char can be invoked via "\C-b", "\M-OD", "\M-[D".
It gets very confusing
A sequence can be created in different formats. For example many commands begin with the Escape (or Meta key). This can be written as \e ,\033, 0x1b, or ^[. Where \0 is octal 33 which is hex 1B, ( or decimal 27). It is confusing when you display information with different commands.
Where does \eOD (or \M-OD)come from?
It was a challenge to find this information.
In the Linux terminfo documentation it says
The codes sent by the left arrow, right arrow, up arrow, down arrow, and home keys can be given as kcub1, kcuf1, kcuu1, kcud1, and khome respectively. If there are function keys such as f0, f1, …, f10, the codes they send can be given as kf0, kf1, …, kf10. If these keys have labels other than the default f0 through f10, the labels can be given as lf0, lf1, …, lf10.
The linux command infocmp
infocmp|grep kcu
gave
kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
so this all says the left arrow key maps to backward character. – Phew
Problems
If there was a space after the : I got
readline: delete-char: no key sequence terminator
from the bind command.
Putting the command into my .profile file didn’t work because of the wrong character set.
I could put the command into a shell script, and invoke it – but I could not get it to work from the .profile.