bash tries to print the list in columns but using a bizarre algorithm.
It appears it tries to print it on as many columns as would fit on the terminal (finding out the width of the terminal from $COLUMNS
or the result of ioctl(2, TIOCGWINSZ)
if $COLUMNS
is not set¹), except that if that would result in only one row, it prints it on one column instead.
So here, if you want the list on one column regardless of the width of the terminal, you can either set $COLUMNS
to 1 (not 0 for which bash ignores the value and resorts to querying the terminal device) or to a very large number (COLUMNS=1
or COLUMNS=9999
) though the latter may be less future-proof.
how to use the enter key instead of for example 1
?
You can't. For that, you'd need to implement it by hand similarly to what you're doing for your number prompt.
BTW, in bash², for input validation, you can't use ranges in bracket expressions such as your [0-9]
, as those typically match hundreds of characters besides 0123456789. You need [0123456789]
instead. For instance, in most locales, ¹²³
would not be rejected because those are characters that sort between 0 and 9, and you'd get something like line 12: ¹²³: syntax error: operand expected (error token is "¹²³")
later on when that number is used in the arithmetic expression.
It's relatively harmless here, but it could get worse. For instance in a th_TH.iso885911
locale on a GNU system where ๔
(Thai digit 4) is between 0 and 9, is encoded as a single byte and classified as [:alpha:]
:
$ LC_ALL=th_TH.iso885911 luit
$ env '๔๔=a[$(reboot)]' bash ./your-script
enter number [4-999]: ๔๔
System rebooting now...
1) yes
2) change your entered number
3) generate a new random number
4) exit this script
Is 0 ok?
๔๔
was not rejected because that matches [1-9][0-9]
, and in an arithmetic expression, since that's what the locale claims is 2 letters, was taken as a variable name, and its value was expanded into the arithmetic expression, causing reboot
to be run.
More on that at Security Implications of using unsanitized data in Shell Arithmetic evaluation.
Also beware the behaviour of read
is dependant on the current value of $IFS
. With the default value of $IFS
, leading and trailing space and tab characters are removed. If called in a context where $IFS
may have been modified, it could have more annoying consequences, which is why when using read
, it's good practice to set $IFS
to the value you want such as:
IFS= read -rp 'Prompt: ' value
To not do any stripping. More on that at Understanding "IFS= read -r line".
¹ when run interactively bash sets $COLUMNS
by itself, not in scripts.
² in its globs, and depending on the system and the C library bash was built against, in regexps used in [[ =~ ]]
.