How to create a selection menu using the select statement in Bash shell

We all very often use bash scripts to automatize boring and repetitive tasks. Sometimes in our scripts we need to ask
the user to perform one or more choices interactively: in this tutorial we will see how to use the Bash shell select statement to perform such operation in very few lines of code.

In this tutorial you will learn:

  • How to use the Bash select statement
  • How to customize the select menu prompt

How to create a selection menu using the select statement in Bash shell

How to create a selection menu using the select statement in Bash shell

Software Requirements and Conventions Used

Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Distribution-independent
Software The Bash shell
Other No special requirements
Conventions # – requires given linux commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux commands to be executed as a regular non-privileged user

The select statement

Scripting is one of the most common skills a system administrator should possess, in order to automate repetitive
tasks and make them less prone to error. In not too complex cases, the shell is the perfect tool to use for the job. Bash, the Bourne Again Shell, is the most used shell in the GNU/Linux world. This shell provides the very useful select statement. Its purpose is described in the following way:

Select words from a list and execute commands



The description is pretty self-explanatory. The statement allows us to interactively receive an input from a user, generating a numbered list of choices and prompting him to select one. Let’s see how it is used:

select NAME [in WORDS ... ;] do COMMANDS; done

The syntax is very similar to that of a traditional for loop in Bash, except for the use of the select keyword. The select statement, however, works in a different way. Let’s see an example. Suppose we want to ask an user to select one of the files contained in a directory. Here is what we could write:

$ files="$(ls -A .)"
$ select filename in ${files}; do echo "${file}"; done
1) file1
2) file2
3) file3
#?

Let’s explain what have we done. First of all we obtained a list of all the files present in the directory (in this case the current working directory) using the ls command and specifying the -A option (short for --almost-all), in order to exclude the implied  . and .. from the returned list, that we assigned to the files variable.

We then proceeded to use the select statement. The above is a very basic example: we provided the result of the expansion of the file variable as the list of choices to be included. Notice that we avoided quoting the expansion ${files} on purpose, in order to obtain word splitting: when an expansion is quoted with double quotes word splitting is suppressed, so spaces are not used as words delimiters and the result of the expansion is considered as a whole. This is not what we want in this case: we need each word to be used as a choice in the generated menu.



The words obtained from the expansion of the variable are printed on the stderr (standard error). Each one is preceded and associated with a number, which is what the user will use to reference it. After all the elements are displayed, the user is prompted to enter its choice. What is displayed is the PS3 prompt, which, by default is set to #?.

What happens when the user performs a selection? Let’s see:

$ files="$(ls -A .)"
$ select filename in ${files}; do echo "You selected ${filename}"; done
1) file1
2) file2
3) file3
#? 1
You selected file1
#?

The choice we entered, 1, is read from the stdin (standard input) and if the entered number is among the available ones, the corresponding word (“file1” in the example) is assigned to the,filename variable. In our example we specified echo "${filename}" as the command to be executed once the choice is performed: as the result: the selected word is printed onscreen. The number we enter to specify our choice is also stored in a variable:  REPLY.

You may notice a strange thing happened in the example above: once we performed our choice, after the execution of the command, we were prompted again for a choice, why? This happened because we didn’t provide a break
command. We can easily fix this:

$ files="$(ls -A .)"
$ select filename in ${files}; do echo "You selected ${filename}"; break; done
1) file1
2) file2
3) file3
#? 1
You selected file1

What if we don’t provide any selection? The prompt is simply repeated until we do:

select filename in ${files}; do echo "You selected ${filename}"; break; done
1) file1
2) file2
3) file3
#?
1) file1
2) file2
3) file3
#?

What if we enter a number which is not in the list instead? In this case the variable we use, filename in our case, is set to null.

Changing the selection prompt

As we already saw, the prompt used by the shell in the context of a select statement is the PS3 prompt, which by default, has the #? string has a value. This is not very user friendly, so we may want to change it and use something more descriptive instead. How can we do that? Very simple: we must change the value of the PS3 parameter:

$ PS3="Please enter your choice: "


The next time we will use the select statement, we will notice the change:

select filename in ${files}; do echo "You selected ${filename} ${REPLY}"; break; done
1) file1
2) file2
3) file3
Enter your choice:

The change made to the variable will be effective only for the current shell section, and, if  we export the variable, also in all its children:

$ export PS3="Please enter your choice: "

The change, however, remains temporary until we set the PS3 variable inside the .bashrc file. PS3 is just one of the prompts used in Bash: check our bash prompt article if you want to know more on the subject.

Conclusions

In this tutorial we learned how to use the Bash select statement. We saw how it works, and how we can use it to create a selection menu to interactively ask an user to perform a choice. Finally we saw how to customize the prompt displayed in the selection menu by modifying the shell PS3 parameter.



Comments and Discussions
Linux Forum