前言
在 Linux bash 里面可以使用 read 内置命令来读取用户输入,当在 while 循环中不断调用 read 命令,并打印一些提示字符,如 $、#、> 等,就可以不断接收用户输入,然后执行一些自定义的命令,看起来就像是一个简易的 shell。
本系列文章使用 read 命令逐步模拟简易的 shell 效果,并实现一个小游戏,从中说明 read 命令的常见用法。
本篇文章主要说明下面的内容:
- read 命令介绍
- 使用 -p 选项指定提示字符串
read 命令介绍
在 bash 中,read 内置命令可以读取用户的一行输入,并对输入内容进行单词拆分,依次赋值给指定的变量。查看 help read 的说明如下:
read: read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
Read a line from the standard input and split it into fields.
Reads a single line from the standard input, or from file descriptor FD if the -u option is supplied. The line is split into fields as with word splitting, and the first word is assigned to the first NAME, the second word to the second NAME, and so on, with any leftover words assigned to the last NAME. Only the characters found in $IFS are recognized as word delimiters.
If no NAMEs are supplied, the line read is stored in the REPLY variable.
Exit Status:
The return code is zero, unless end-of-file is encountered, read times out (in which case it's greater than 128), a variable assignment error occurs, or an invalid file descriptor is supplied as the argument to -u.
即,read 命令从标准输入读取到一行,每行内容以换行符结尾,但是读取到的内容不包含行末的换行符。
对于读取到的内容,会按照 bash 的 IFS 全局变量保存的分割字符把输入行拆分成多个单词,把这些词依次赋值给提供的变量,如果所给的变量个数少于分割后的单词数,最后一个变量被赋值为剩余的所有单词。
举例说明如下:
$ read first second third last1 2 3 4 5 678$ echo $first, $second, $third, $last1, 2, 3, 4 5 678$ read input_lineThis is a test input line.$ echo $input_lineThis is a test input line.
可以看到,默认基于空格来拆分单词,所给的第一个 first 变量被赋值为拆分后的第一个单词,第二个 second 变量被赋值为拆分后的第二个单词,第三个 third 变量被赋值为拆分后的第三个单词,最后一个 last 变量被赋值为第三个单词后的所有单词。
显然,只提供一个变量时,整个输入行都会赋值给这个变量,打印的 input_line 变量值可以看到这一点。
使用 -p 选项指定提示字符串
执行 read 命令时,默认不打印提示字符串,如果想要引导用户输入特定的内容,可以使用 -p 选项来指定提示字符串。查看 help read 对该选项的说明如下:
-p prompt
output the string PROMPT without a trailing newline before attempting to read
即,在 -p 选项后面跟着一个 prompt 字符串,在读取用户输入之前,会先打印这个 prompt 字符串,以作提示。这个提示字符串后面不会换行,会跟用户的输入在同一行。具体举例说明如下:
$ read -p "Please input your mood today: " moodPlease input your mood today: happy$ echo $moodhappy
在执行所给的 read 命令时,会先打印 “Please input your mood today: ”字符串,没有换行,等待用户输入。上面的 “happy” 是输入的字符串,会被赋值给指定 mood 变量。
当使用 while 循环不断调用 read 命令,且用 -p 选项指定 $ 字符时,看起来就像是一个简易的 shell,可以根据用户输入做一些处理,也可以指定其他字符,如 >、# 等。
假设有一个 tinyshell.sh 脚本,内容如下:
#!/bin/bashwhile read -p "tinyshell> " input; do if [ "$input" == "l" ]; then ls elif [ "$input" == "quit" ]; then break else echo "Unknown input: $input" fidone
该脚本在 while 循环中不断调用 read 命令,使用 -p 选项设置提示字符串为 “tinyshell> ”,DOS 命令行的提示字符就是 >。具体执行结果如下:
$ ./tinyshell.shtinyshell> ltinyshell.shtinyshell> dUnknown input: dtinyshell> quit$
在执行时,先打印出 “tinyshell> ” 提示字符串,等待用户输入。
这里输入 l 字符,脚本会执行 ls 命令。
输入 quit 字符串,会退出 while 循环,终止执行。
输入其他内容则提示 “Unknown input: ”。
在实际工作中,对这个例子进行扩展,就能模拟一个简易的 shell 效果,可以输入自定义的命令简写,来执行一长串的命令,非常方便。
例如进行 Android 系统开发,经常需要执行 adb shell 的各种命令,有些命令带有很多参数,比较难输入,仿照这个例子,可以只输入一个字符、或者几个字符,然后执行对应的 adb shell 命令,减少很多输入。