处理用户输入
命令行参数
读取参数
./test 10 30
10和30即命令行参数
$0保存程序名(即./test),$1是第一个参数,$2是第二个......${10}第十个参数,两位数以上则用大括号括起来
各参数通过空格区分,如果参数本身含有空格,则添加引号
./test "Rich Blum"
读取脚本名
$0存在的问题:保存的是程序名包括路径
basename命令
echo $(basename $0)
若程序名为/home/xxx/test.sh,则输出test.sh
其实,basename仅仅是一个字符串截取工具,截取最后一部分即是文件名,对应的有dirname命令,截取目录名(在本例中为/home/xxx)
特殊参数变量
$#参数
记录了命令行参数个数
虽然$#可以当作普通变量使用,但是注意$f符号嵌套使用内部$要用!代替:
echo ${$#} #试图输出最后一个参数,但是是错误写法
#正确写法:
echo ${!#}
$*和$@参数
二者都是获取全部命令行参数,但是前者将所有参数视为一个整体(即当成一个长字符串),后者相当于参数的数组
移动参数
shift命令
通过shift命令可以将命令行参数依次左移,有下例子:
count=1
while [ -n "$1" ] ; do
echo "Parameter #$count:"$1
count=$[$count+1]
shift
done
./test.sh a b c d
输出如下:
Parameter #1:a
Parameter #2:b
Parameter #3:c
Parameter #4:d
shift参数也可以指定左移位数:
shift 2 #左移两位
处理命令选项
使用getopts命令
使用格式:
getopts optstring variable
如果选项字母有参数值,就在后面加一个冒号,参数保存在variable(用户自定义)中,参数值保存在OPTARG中;要去掉错误消息的话也是在optstring前加冒号;OPTIND记录了正在处理的参数位置。
有如下例子:
while getopts :ab:c opt ; do
case "$opt" in
a) echo "Found the -a option" ;;
b) echo "Found the -b option,with value : $OPTARG" ;;
c) echo "Found the -c option" ;;
*) echo "Unknown option:$opt" ;;
esac
done
./test.sh -a -b test -c -d
输出:
Found the -a option
Found the -b option,with value : test
Found the -c option
Unknown option:?
注意到:未列出的选项getopts统一记录为?
获取用户输入-read命令
基本读取
-p:指定提示信息
$ read -p "Please input your age:" age
Please input your age: 10
read将读取到的值存入用户定义的变量中(上例中为age),另外如果不指定变量,则read默认将输入值存入环境变量REPLY中
-t:指定超时时间
$ read -t 5 -p "Please input your age:" age
上例中,read指定超时时间为5秒,超时后read返回非零状态码
-n:后接数字表示接收几个字符后退出
$ read -n1 -p "Do you want do this [Y/N] ?" answer
用户输入一个字符后read立马返回,不用按回车键
-s:隐藏输入的数据(实际上read是将文字颜色设置为背景颜色)
$ read -s -p "Enter your password:" password
屏幕上不会出现用户输入的字符
从文件中读取
常见的方法是使用cat加管道符:
cat text | while read line
do
echo $line
done
text中内容如下:
hello,world
beautiful love
注意,text文件中末尾空行必须有,否则有内容的最后一行将无法输出(我也不知道啥原因)
./test.sh
输出:
hello,world
beautiful love
文件IO
输入/输出重定向
Linux文件描述符
Linux用文件描述符来标识每个文件对象,每个进程最多可以有九个文件描述符(0~8),bash保留了前三个:
0:STDIN,即标准输入
1:STDOUT,即标准输出
2:STDERR,即标准错误输出
对文件描述符指向的文件,可以通过&来引用:
$ echo "hello,world" > &2
上述指令将echo输出到文件描述符2所指向的文件
重定向符号(<,>)
<:输入重定向,用指定文件代替标准输入
>:输出重定向,用指定文件代替标准输出。注意:标准错误输出并没有被重定向,依然为屏幕
重定向标准错误输出
只重定向错误输出,使用 2>:
$ ls -al badfile 2> test4
"2>"的意思是将文件描述符2(也就是STDERR)指向后面的文件
重定向标准输出和错误输出,使用 &>
$ ls -al badfile &> test7
在这种情况中,bash自动赋予错误信息更高的优先级,错误消息显示在文本开头
在脚本中永久重定向,使用exec命令
exec 1>testout
上述指令将1(也就是STDOUT)指向testout
exec 0< testfile
上述指令将0(也就是标准输入)指向testfile
----
对文件描述符的使用就像使用指针
关闭文件描述符
exec 3> &-
上述指令将3文件描述符关闭
15.6 阻止命令输出
null文件
将输出写入到null文件,null文件将不含任何内容:
$ ls -al > /dev/null
$ cat /dev/null
$
可以使用null文件作为清空文件的一种手段:
$ cat /dev/null > testfile
$ cat testfile
$
15.7 创建临时文件
Linux使用/temp目录来保存临时文件,启动时自动删除里面的内容。
使用 mktemp 命令
创建本地临时文件
默认情况下,mktemp会在本地目录创建一个临时文件,你只需要指定一个文件名模板就可以了,模板包含任意文件名后跟6个X:
$ mktemp testing.XXXXXX
testing.P1xKkI
$ ls -al testing*
-rw------- 1 root root 0 Feb 25 00:26 testing.P1xKkI
在脚本中使用时,需要使用mktemp命令返回的文件名:
tempfile=$(mktemp testing.XXXXXX)
在/temp目录创建临时文件
使用-t选项,mktemp命令返回完整路径名,而不仅仅是文件名:
$ mktemp -t testing.XXXXXX
/tmp/testing.5V2lT1$ ls -al /tmp/testing*
-rw------- 1 root root 0 Feb 25 00:31 /tmp/testing.5V2lT1
创建临时目录
使用-d选项创建一个临时目录
tempdir=$(mktemp -d tempdir.XXXXXX)
cd $tempdir
tempfile=$(mktemp testing1.XXXXXX)
exec 7>$tempfile
echo "这是一个临时文件内容" >&7
第16章 控制脚本
16.1 处理信号
常见Linux信号
信号 | 值 | 描述 |
---|---|---|
1 | SIGHUP | 挂起进程 |
2 | SIGINT | 终止进程 |
3 | SIGQUIT | 停止进程 |
9 | SIGKILL | 杀死进程 |
15 | SIGTERM | 尽可能终止进程 |
17 | SIGSTOP | 无条件停止进程 |
18 | SIGTSTP | 停止或暂停进程 |
19 | SIGCONT | 继续运行停止的进程 |
生成信号
1.中断进程
Ctrl+C组合键,生成SIGINT信号,终止进程
2.Ctrl+Z组合键,生成SIGTSTP信号,停止进程,进程仍在内存中保留,并且能恢复继续执行
$ sleep 100
^Z
[1] + 19832 suspended sleep 100
方括号是shell分配给进程的唯一的作业号 。
可以使用ps -l查看已停止进程:
$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 13882 13665 0 80 0 - 36763 sigsus pts/4 00:00:00 zsh
0 T 0 19832 13882 0 80 0 - 27014 do_sig pts/4 00:00:00 sleep
0 R 0 20206 13882 0 80 0 - 38332 - pts/4 00:00:00 ps
在S状态栏为T的表示已停止
捕获信号
trap commands signals
示例:
trap "echo 'Sorry,I have trapped Ctrl-C'" SIGINT
echo "This is a test script"
count=1
while [ $count -le 10 ] ; do
echo "Loop #$count"
sleep 1
count=$[$count+1]
done
echo "The test script is over"
$ ./test.sh
This is a test script
Loop #1
Loop #2
^CSorry,I have trapped Ctrl-C
Loop #3
Loop #4
^CSorry,I have trapped Ctrl-C
Loop #5
Loop #6
^CSorry,I have trapped Ctrl-C
Loop #7
Loop #8
Loop #9
Loop #10
The test script is over
恢复默认信号行为
trap -- SIGINT
单破折号也可以
16.2 以后台模式运行脚本
在命令后加&符号即可后台启动脚本
如果终端会话退出,该终端会话的所有后台进程也会随之退出
16.3 在非控制台下运行后台脚本
使用nohup命令来阻断发送给进程的SIGHUP信号
因为使用nohup命令后,进程与终端失去联系,进程的STDOUT和STDERR重定向到名为nohup.out的文件中,