GRABCHARS(1)

NAME
grabchars - get keystrokes directly from user

SYNOPSIS
grabchars [options]

grabchars select [options] list

grabchars select-lr [options] list

DESCRIPTION
Grabchars gets characters from the user as they are typed in, without having to wait for the return key to be pressed. Among other things, this allows shell scripts to be written with highly interactive menus.

By default, grabchars will obtain one character from stdin, echo that character to stdout, and return with a status of one; meaning one character read.

In addition to the basic character-reading mode, grabchars provides a positional mask mode (-m), a filter-as-you-type vertical selection menu (select), and a horizontal selection menu (select-lr).

OPTIONS

-b  Both stdout and stderr are used for output. This is useful for setting a variable in a shell script and echoing a keystroke to the screen at the same time.

-c<valid characters>
    Only characters in <valid characters> are accepted. Regular expressions such as [a-z] may be used to specify ranges. All other characters are ignored.

-C<excluded characters>
    The inverse of -c. Rejects characters that match the pattern; accepts everything else. Uses the same character class syntax as -c. Both flags may be combined: a character must match -c AND not match -C.

-d<char(s)>
    Default char or string to output if the user hits RETURN or lets grabchars timeout. The status that is returned is the same as if the user had typed in the character or string, so this option may be used with the -s (silent) flag.

-e  Output goes to stderr rather than stdout.

-E

-E1 Enable line editing. Arrow keys, Home, End, Backspace, Delete, Ctrl-K, Ctrl-U, and Ctrl-W are active. When -n is greater than 1, editing is on by default. See LINE EDITING below.

-E0 Disable line editing. Backspace and arrow keys are treated as raw bytes, not editing commands. Useful when you want to capture every keystroke exactly as typed.

-f  Flush any previous input. By default, grabchars will see any characters present in stdin, which allows for some typeahead in shell scripts.

-h  Help/usage screen.

-H<r|b|a>
    Highlight style for select-lr mode. -Hr uses reverse video (default); -Hb uses bracket style ([option]); -Ha uses arrow style (>option<). Bracket and arrow styles are useful on terminals where reverse video is unavailable or hard to see.

-L  Map characters to lower case.

-m<mask>
    Positional input validation. Each character position is validated against a corresponding element in the mask pattern. Characters that do not match the mask at the current position are silently rejected. Literal characters in the mask (parens, dashes, slashes, etc.) are auto-inserted into the display as the user types. The mask length determines the character count (like an implicit -n). See MASK SYNTAX below.

-n<number>
    Number of characters to read. By default, grabchars looks for one character.

-p<prompt>
    Sets up a prompt for the user, printed to stdout. See EXAMPLES.

-q<prompt>
    Sets up a prompt for the user, printed to stderr rather than stdout. This is almost always the right choice in scripts, because stdout can then be captured with $().

-r  The RETURN key exits. Use this with the -n option to allow for variable numbers of characters to be typed in. In mask mode with quantifiers, Enter also accepts partial input when all required mask elements have their minimum counts satisfied.

-R  Raw byte mode. Every byte read from the terminal is collected as-is, without escape-sequence parsing. This means arrow keys and other multi-byte sequences count as multiple bytes toward -n. The flags -c, -C, -U, -L, and -E are silently ignored in raw mode. See RAW MODE below.

-s  Silent. Do not output anything. Just return a status.

-t<seconds>
    Time to allow the user to respond. By default, the user can take as long as he or she wants to. The timeout option allows you to write shell scripts where you can offer some assistance if it's obvious that the user might be stuck. If a default (-d) is set and the user has typed nothing, the default is returned on timeout; otherwise the exit code is 254.

-U  Map characters to upper case. Note that if -U and -L are both specified on the command line, the last one that occurs will win out.

-Z0 Suppress the trailing newline that grabchars normally prints to stderr after input is complete.

-Z1 Re-enable the trailing newline (the default).

--version
    Print the version string and exit with code 0.

SUBCOMMANDS

  grabchars select list [options]
Choose from a comma-separated list with filter-as-you-type narrowing. The selected option text is written to stdout. The exit code is the 0-based position of the chosen option in the original list.

list is a comma-separated string of options, e.g. "red,green,blue". To load options from a file, use --file filename.

Controls:

    type
        Narrow the list (filter-as-you-type)

    Backspace
        Widen the filter

    Up / Down
        Cycle through matching options

    Tab Fill filter with full name of current match

    Enter
        Confirm selection; output to stdout

    Escape
        Cancel; no output; exit code 255

Options -d, -t, -q, -e, -b, -f, and -Z0/-Z1 all apply in select mode.

  grabchars select-lr list [options]
Horizontal selection. All matching options are shown on one line, with the current selection highlighted. Type to filter, Left/Right (or Up/Down) to move, Enter to confirm, Escape to cancel.

list is a comma-separated string of options, e.g. "red,green,blue". To load options from a file, use --file filename (one option per line), the same as in select mode.

Accepts the same options as select, plus -H<r|b|a> for highlight style.

LINE EDITING
When -n is greater than 1, line editing is active by default (equivalent to -E1). Disable with -E0. Force on for a single character with -E.

Key             Action
---------------  -----------------------------------
Left / Ctrl-B   Move cursor left one character
Right / Ctrl-F  Move cursor right one character
Home / Ctrl-A   Move to beginning of line
End / Ctrl-E    Move to end of line
Backspace       Delete character before cursor
Delete / Ctrl-D Delete character under cursor
Ctrl-K          Kill (delete) from cursor to end of line
Ctrl-U          Kill from beginning of line to cursor
Ctrl-W          Kill word backward

MASK SYNTAX
A mask is specified with -m"pattern" and constrains input position by position. Literal characters in the pattern (parentheses, slashes, dashes, etc.) are auto-inserted into the display as the user types.

Mask character classes:

Code  Accepts                 Character set
----  ---------------------   ------------------------
U     Uppercase letter        [A-Z]
l     Lowercase letter        [a-z]
c     Alphabetic character    [A-Za-z]
n     Digit                   [0-9]
x     Hexadecimal digit       [0-9A-Fa-f]
p     Punctuation             [!-/:-@[-`{-~]
W     Whitespace              space or tab
[...] Custom character class  same syntax as -c

Any character not listed above is treated as a literal and will be auto-inserted. To use a mask code character as a literal, escape it with a backslash (e.g., \\n for a literal n).

Quantifiers (follow the preceding mask element):

*   Zero or more (greedy; requires Enter to complete)
+   One or more (greedy; requires Enter to complete)
?   Zero or one (optional)

Quantifiers cannot be applied to literal characters.

RAW MODE
With -R, grabchars bypasses its escape-sequence parser. Every byte received from the terminal is collected as-is; multi-byte sequences such as arrow keys (ESC [ A = three bytes for Up) count as three bytes toward -n.

Raw mode is useful for key-binding capture, debugging what byte sequences a terminal sends, or any situation where you need the exact bytes that keys produce.

Output is binary; pipe to xxd(1) or od(1) to inspect:

    grabchars -R -n 3 | xxd

EXAMPLES

grabchars
    gets one keystroke

grabchars -caeiou
    get one of the vowels

grabchars -c i
    get the letter 'i'

grabchars -C aeiou
    get any character except a vowel

grabchars '-penter a letter '
    print the prompt "enter a letter "

grabchars '-qenter a letter '
    print the prompt ('q' for question) "enter a letter " through stderr.

grabchars -n4
    get four characters.

grabchars -d a
    If the first character typed is a RETURN, expand it to 'a'.

grabchars -d gumby
    If the first character typed is a RETURN, expand it to "gumby".

grabchars -r
    The RETURN key will exit grabchars. You would use this with the -n option, so that variable numbers of characters may be entered.

grabchars -n 4 -r -t 10
    Accept up to four characters, or exit when RETURN is hit, or exit when 10 seconds have elapsed.

grabchars -t2
    timeout after two seconds.

grabchars -d gumby -t2
    If the first character typed is a RETURN, or if two seconds have gone by, pretend that the user typed in "gumby".

grabchars -n3 -p 'initials: '
    print a prompt and grab three characters.

grabchars -c 0123456789 -n2 -t10
    get two numbers with a ten second timeout.

grabchars -m (nnn) nnn-nnnn -q Phone:
    read a full phone number with auto-inserted punctuation.

grabchars -m nn/nn/nnnn -q Date (MM/DD/YYYY):
    read a date; slashes are inserted automatically.

grabchars -m #xxxxxx -q Hex color:
    the leading # is auto-inserted; read six hex digits.

grabchars select yes,no,cancel -q Action:
    present a filter-as-you-type vertical menu.

grabchars select-lr small,medium,large -q Size:
    present a horizontal selection menu.

grabchars -R -n 3 -q Press an arrow key:  | xxd
    capture raw bytes; an arrow key produces three bytes (e.g. 1b 5b 41).

Note that arguments like "-n4" or "-n 4" are handled the same way.

DIAGNOSTICS
Grabchars returns the number of characters (or bytes, in raw mode) successfully read — typically 1 for a single keystroke.

Special exit codes:

254   Timeout with no input and no default set
255   Escape pressed, bad arguments, or other error
0     --version flag

In select and select-lr modes, the exit code is the 0-based index of the chosen option in the original list (0 = first option, 1 = second, etc.). Escape returns 255; timeout without a default returns 254.

SEE ALSO
sh(1), bash(1), read(1), xxd(1), od(1)

Full documentation is in the source distribution:

README.md       -- flag reference
docs/cookbook.md  -- 21 runnable examples
docs/maskInput.md -- mask syntax reference
docs/RAW-MODE.md  -- raw byte mode reference

AUTHOR
Dan Smith

Originally written by me, in C, in 1988 and posted to comp.sources.misc. Rewritten in Rust in 2025–2026 as grabchars 2.0.

Source: https://github.com/DanielSmith/grabchars