上篇回顾:
- function main() {
- if $cygwin; then
- # Workaround for issue involving JLine and Cygwin
- # (see http://sourceforge.net/p/jline/bugs/40/).
- # If you're using the Mintty terminal emulator in Cygwin, may need to set the
- # "Backspace sends ^H" setting in "Keys" section of the Mintty options
- # (see https://github.com/sbt/sbt/issues/562).
- stty -icanon min 1 -echo > /dev/null 2>&1
- export SPARK_SUBMIT_OPTS="$SPARK_SUBMIT_OPTS -Djline.terminal=unix"
- "${SPARK_HOME}"/bin/spark-submit --class org.apache.spark.repl.Main --name "Spark shell" "$@"
- stty icanon echo > /dev/null 2>&1
- else
- export SPARK_SUBMIT_OPTS
- "${SPARK_HOME}"/bin/spark-submit --class org.apache.spark.repl.Main --name "Spark shell" "$@"
- fi
- }
- # Copy restore-TTY-on-exit functions from Scala script so spark-shell exits properly even in
- # binary distribution of Spark where Scala is not installed
- exit_status=127
- saved_stty=""
- # restore stty settings (echo in particular)
- function restoreSttySettings() {
- stty $saved_stty
- saved_stty=""
- }
- function onExit() {
- if [[ "$saved_stty" != "" ]]; then
- restoreSttySettings
- fi
- exit $exit_status
- }
- # to reenable echo if we are interrupted before completing.
- trap onExit INT
- # save terminal settings
- saved_stty=$(stty -g 2>/dev/null)
- # clear on error so we don't later try to restore them
- if [[ ! $? ]]; then
- saved_stty=""
- fi
- main "$@"
- # record the exit status lest it be overwritten:
- # then reenable echo and propagate the code.
- exit_status=$?
- onExit
总结一下,上面的代码大体上做了三件事:
下面我们就循序渐进学习下这半段脚本涉及的内容:
命令支持捕获特定的信号,然后执行某个命令。常用的用法有:
- trap
- trap "commands" signal-list 捕获到特定的信号,执行commands命令
- trap signal-list 捕获特定的信号,停止当前进程
- trap " " signal-list 捕获特定的信号,什么也不做
支持的信号,可以利用
查询到:
- kill- l
- [root@localnode3 test]# kill -l
- 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
- 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
- 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
- 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
- 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
- 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
- 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
- 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
- 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
- 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
- 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
- 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
- 63) SIGRTMAX-1 64) SIGRTMAX
- SIGHUP 终止进程 终端线路挂断
- SIGINT 终止进程 中断进程
- SIGQUIT 建立CORE文件 终止进程,并且生成core文件
- SIGILL 建立CORE文件 非法指令
- SIGTRAP 建立CORE文件 跟踪自陷
- SIGBUS 建立CORE文件 总线错误
- SIGSEGV 建立CORE文件 段非法错误
- SIGFPE 建立CORE文件 浮点异常
- SIGIOT 建立CORE文件 执行I/O自陷
- SIGKILL 终止进程 杀死进程
- SIGPIPE 终止进程 向一个没有读进程的管道写数据
- SIGALARM 终止进程 计时器到时
- SIGTERM 终止进程 软件终止信号
- SIGSTOP 停止进程 非终端来的停止信号
- SIGTSTP 停止进程 终端来的停止信号
- SIGCONT 忽略信号 继续执行一个停止的进程
- SIGURG 忽略信号 I/O紧急信号
- SIGIO 忽略信号 描述符上可以进行I/O
- SIGCHLD 忽略信号 当子进程停止或退出时通知父进程
- SIGTTOU 停止进程 后台进程写终端
- SIGTTIN 停止进程 后台进程读终端
- SIGXGPU 终止进程 CPU时限超时
- SIGXFSZ 终止进程 文件长度过长
- SIGWINCH 忽略信号 窗口大小发生变化
- SIGPROF 终止进程 统计分布图用计时器到时
- SIGUSR1 终止进程 用户定义信号1
- SIGUSR2 终止进程 用户定义信号2
- SIGVTALRM 终止进程 虚拟计时器到时
最常用的信号有四个,
, 使用的时候可以简写:
- SIGHUP,SIGINT,SIGQUIT,SIGTSTP
- trap "" 1 2 3 24
- 或
- trap "" HUP INT QUIT TSTP
然后我们回头看看源码:
- trap onExit INT
这句是说,捕获 INT 中断信号,然就执行 onExit 方法。onExit 中判断是否恢复终端设置。
- exit_status=127
- saved_stty=""
- # restore stty settings (echo in particular)
- function restoreSttySettings() {
- stty $saved_stty
- saved_stty=""
- }
- function onExit() {
- if [[ "$saved_stty" != "" ]]; then
- restoreSttySettings
- fi
- exit $exit_status
- }
stty 命令可以用来改变终端的显示,比如说关闭一些按键,开启一些特殊字符的输入等等。
这个命令最常用的就是下面几个:
- -a,--all 以人可读的方式打印所有当前设置;-a参数比单独的stty命令输出的终端信息更详细
- -g,--save 以stty可读的方式打印当前所有设置
- -F,--file=DEVICE 打开并使用特定的设备((DEVICE)以代替标准输入(stdin)
- --help 显示帮助并退出
- --version 显示版本并退出
- stty size 打印终端行数和列数
我们先来试试
这个命令
- stty size
- 40 100
它就是打印出来了终端显示的行数和列数。
再看看
,看看都有什么内容:
- stty -a
- speed 38400 baud;
- rows 40;
- columns 100;
- line = 0;
- intr = ^C;
- quit = ^\;
- erase = ^?;
- kill = ^U;
- eof = ^D;
- eol = <undef > ;
- eol2 = <undef > ;
- swtch = <undef > ;
- start = ^Q;
- stop = ^S;
- susp = ^Z;
- rprnt = ^R;
- werase = ^W;
- lnext = ^V;
- flush = ^O;
- min = 1;
- time = 0; - parenb - parodd cs8 - hupcl - cstopb cread - clocal - crtscts - cdtrdsr - ignbrk - brkint - ignpar - parmrk - inpck - istrip - inlcr - igncr icrnl ixon - ixoff - iuclc - ixany - imaxbel - iutf8 opost - olcuc - ocrnl onlcr - onocr - onlret - ofill - ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok - echonl - noflsh - xcase - tostop - echoprt echoctl echoke
最开始 speed 是终端输入和输出的速度,单位是(位 / 秒),常用的有 50、75、110、134、200、300、600、1200、1800、2400、4800、9600、19200、19.2、38400、38.4、exta 和 extb。具体还得看硬件是否支持。
后面显示了终端的基本信息,以及一些常用的按键。比如
- intr 表示中断
- quit 表示退出
- erase 表示擦除最后一个字符
- kill 表示擦除当前航
- eof 表示文件结束
- eol 表示当前行结束
- eol2 可以设置两个字符
- swtch 表示切换外壳
- start 表示停止输出后重新开始
- stop 表示停止输出
- susp 表示终端停止
- rprnt 表示刷新当前行
- werase 表示擦除最后一个单词
- lnext 表示输入下一个字符
- flush ?????
再看后面:
- min = 1;
- time = 0;
通常与 icaon 搭配使用,表示一次读操作至少多少个字符
- min = 1
表示读超时的时间,N/10 秒。
- time = 0
在后面一大堆的内容是 stty 支持的功能,详细的可以参考:
- clocal 假定一行没有调制解调器控制。
- -clocal 假定一行带有调制解调器控制。
- cread 启用接收器。
- -cread 禁用接收器。
- cstopb 每个字符选择两个停止位。
- -cstopb 每个字符选择一个停止位。
- cs5, cs6, cs7, cs8 选择字符大小。
- hup,hupcl 最后关闭时挂起拨号连接。
- -hup,-hupcl 最后关闭时不挂起拨号连接。
- parenb 启用奇偶性校验的生成和检测。
- -parenb 禁用奇偶性校验的生成和检测。
- parodd 选择奇校验。
- -parodd 选择偶校验。
- 0 立即挂起电话线路。
- speed 将工作站输入和输出速度设置为指定的 speed 数(以位/秒为单位)。并不是所有的硬件接口都支持所有的速度。speed 的可能值有:50、75、110、134、200、300、600、1200、1800、2400、4800、9600、19200、19.2、38400、38.4、exta 和 extb。
- 注:
- exta、19200 和19.2 是同义词;extb、38400 和38.4 是同义词。
- ispeed speed 将工作站输入速度设置为指定的 speed 数(以位/秒为单位)。并不是所有的硬件接口都支持所有的速度,而且并不是所有的硬件接口都支持该选项。speed 的可能值与speed 选项相同。
- ospeed speed 将工作站输出速度设置为指定的 speed 数(以位/秒为单位)。并不是所有的硬件接口都支持所有的速度,而且并不是所有的硬件接口都支持该选项。speed 的可能值与speed 选项相同。
- brkint 中断时发出 INTR 信号。
- -brkint 中断时不发出 INTR 信号。
- icrnl 输入时将 CR 映射为 NL。
- -icrnl 输入时不将 CR 映射为 NL。
- ignbrk 输入时忽略 BREAK。
- -ignbrk 输入时不忽略 BREAK。
- igncr 输入时忽略 CR。
- -igncr 输入时不忽略 CR。
- ignpar 忽略奇偶错误。
- -ignpar 不忽略奇偶错误。
- inlcr 输入时将 NL 映射为 CR。
- -inlcr 输入时不将 NL 映射为 CR。
- inpck 启用奇偶校验。
- -inpck 禁用奇偶校验。
- istrip 将输入字符剥离到 7 位。
- -istrip 不将输入字符剥离到 7 位。
- iuclc 将大写字母字符映射为小写。
- -iuclc 不将大写字母字符映射为小写。
- ixany 允许任何字符重新启动输出。
- -ixany 只允许 START(Ctrl-Q 按键顺序)重新启动输出。
- ixoff 当输入队列接近空或满时,发送 START/STOP 字符。
- -ixoff 不发送 START/STOP 字符。
- ixon 启用 START/STOP 输出控制。一旦启用 START/STOP 输出控制,您可以按下 Ctrl-S 按键顺序暂停向工作站的输出,也可按下 Ctrl-Q 按键顺序恢复输出。
- -ixon 禁用 START/STOP 输出控制。
- imaxbel 当输入溢出时,回送 BEL 字符并且废弃最后的输入字符。
- -imaxbel 当输入溢出时,废弃所有输入。
- parmrk 标记奇偶错误。
- -parmrk 不标记奇偶错误。
- bs0, bs1 为退格符选择延迟样式(bs0 表示没有延迟)。
- cr0, cr1, cr2, cr3 为 CR 字符选择延迟样式(cr0 表示没有延迟)。
- ff0, ff1 为换页选择延迟样式(ff0 表示没有延迟)。
- nl0, nl1 为 NL 字符选择延迟样式(nl0 表示没有延迟)。
- ofill 使用延迟填充字符。
- -ofill 使用延迟定时。
- ocrnl 将 CR 字符映射为 NL 字符。
- -ocrnl 不将 CR 字符映射为 NL 字符。
- olcuc 输出时将小写字母字符映射为大写。
- -olcuc 输出时不将小写字母字符映射为大写。
- onlcr 将 NL 字符映射为 CR-NL 字符。
- -onlcr 不将 NL 字符映射为 CR-NL 字符。
- onlret 在终端 NL 执行 CR 功能。
- -onlret 在终端 NL 不执行 CR 功能。
- onocr 不在零列输出 CR 字符。
- -onocr 在零列输出 CR 字符。
- opost 处理输出。
- -opost 不处理输出;即忽略所有其它输出选项。
- ofdel 使用 DEL 字符作为填充字符。
- -ofdel 使用 NUL 字符作为填充字符。
- tab0, tab1, tab2 为水平制表符选择延迟样式(tab0 表示没有延迟)。
- tab3 扩展制表符至多个空格。
- vt0, vt1 为垂直制表符选择延迟样式(vt0 表示没有延迟)。
- echo 回送每个输入的字符。
- -echo 不回送字符。
- echoctl 以 ^X(Ctrl-X)回送控制字符,X 是将 100 八进制加到控制字符代码中给出的字符。
- -echoctl 不以 ^X(Ctrl-X)回送控制字符。
- echoe 以"backspace space backspace"字符串回送 ERASE 字符。
- 注:
- 该模式不保持对列位置的跟踪,因此您可能在擦除制表符和转义序列等符号时得到意外的结果。
- -echoe 不回送 ERASE 字符,只回送退格符。
- echok 在 KILL 字符后回送 NL 字符。
- -echok 在 KILL 字符后不回送 NL 字符。
- echoke 通过擦除输出行上的每个字符,回送 KILL 字符。
- -echoke 只回送 KILL 字符。
- echonl 回送 NL 字符。
- -echonl 不回送 NL 字符。
- echoprt 以 /(斜杠)和 \ (反斜杠) 向后回送擦除的字符。
- -echoprt 不以 /(斜杠)和 \ (反斜杠) 向后回送擦除的字符。
- icanon 启用规范输入(规范输入允许使用 ERASE 和 KILL 字符进行输入行的编辑)。请参阅 AIX 5L Version 5.2 Communications Programming Concepts 中的 Line Discipline Module (ldterm) 中关于canonical mode input 的讨论。
- -icanon 禁用规范输入。
- iexten 指定从输入数据中识别实现性定义的功能。要识别以下控制字符,需要设置 iexten:eol2、dsusp、reprint、discard、werase、lnext。与这些模式关联的功能也需要设置iexten:imaxbel、echoke、echoprt、echoctl。
- -iexten 指定从输入数据中识别实现性定义的功能。
- isig 启用对特殊控制字符(INTR、SUSP 和 QUIT)的字符检查。
- -isig 禁用对特殊控制字符(INTR、SUSP 和 QUIT)的字符检查。
- noflsh 不清除 INTR、SUSP 或 QUIT 控制字符之后的缓冲区。
- -noflsh 清除 INTR、SUSP 或 QUIT 控制字符之后的缓冲区。
- pending 下次读操作暂挂或输入到达时,要重新输入从原始模式转换为规范模式后被暂挂的输入。暂挂是一个内部状态位。
- -pending 没有文本暂挂。
- tostop 为背景输出发出 SIGTOU 信号。
- -tostop 不为背景输出发出 SIGTOU 信号。
- xcase 在输入中回送大写字符,并在输出显示的大写字符之前加上 \ (反斜杠)。
- -xcase 不在输入时回送大写字符。
- 这些选项是对 《X/Open 可移植性指南,发行版 4》 标准的扩展。
- cdxon 输出时启用 CD 硬件流量控制模式。
- -cdxon 输出时禁用 CD 硬件流量控制模式。
- ctsxon 输出时启用 CTS 硬件流量控制模式。
- -ctsxon 输出时禁用 CTS 硬件流量控制模式。
- dtrxoff 输入时启用 DTR 硬件流量控制模式。
- -dtrxoff 输入时禁用 DTR 硬件流量控制模式。
- rtsxoff 输入时启用 RTS 硬件流量控制模式。
- -rtsxoff 输入时禁用 RTS 硬件流量控制模式。
- cooked 请参阅 -raw 选项。
- ek 分别将 ERASE 和 KILL 字符设置为 Ctrl-H 和 Ctrl-U 按键顺序。
- evenp 启用 parenb 和 cs7。
- -evenp 禁用 parenb 并设置 cs8。
- lcase,LCASE 设置 xcase,iuclc 和olcuc。在工作站只以大写字符使用。
- -lcase,-LCASE 设置 -xcase、-iuclc 和-olcuc。
- nl 设置 -icrnl 和-onlcr。
- -nl 设置 icrnl、 onlcr、-inlcr、-igncr、-ocrnl和-onlret。
- oddp 启用 parenb、 cs7 和 parodd。
- -oddp 禁用 parenb 并设置 cs8。
- parity 请参阅 evenp 选项。
- -parity 请参阅 -evenp 选项。
- sane 将参数重新设置为合理的值。
- raw 允许原始模式输入(不包括输入处理,例如 erase、kill 或 interrupt);传回奇偶(校验)位。
- -raw 允许规范输入方式。
- tabs 保留制表符。
- -tabs,tab3 打印时将制表符替换为空格。
- 窗口大小
- cols n,columns n 将终端(窗口)大小记录为有 n 列。
- rows n 将终端(窗口)大小记录为有 n 行。
- size 将终端(窗口)大小打印到标准输出(先是行,再是列)中。
看完上面的东西,很多人都蒙 B 了,这么多东西咋用啊?咱们来个小栗子,体验一下 stty 的奇妙。
场景,当你远程 ssh 机器的时候是不是要输入密码?但是输入的密码是看不到的,这是怎么做到的?先来看看 shell 脚本吧!
- #!/bin/bash
- PASSWD="123"
- USER=`whoami`
- # save current stty setting
- SAVEDSTTY=`stty -g`
- # hide input characters
- stty -echo
- echo -n "Please input passwd:"
- read passwd
- echo ""
- if [ "$PASSWD" = "$passwd" ];then
- echo "Welcome $USER"
- else
- echo "Sorry"
- fi
- # echo input caharacters
- stty echo
- # restore stty
- stty=$SAVEDSTTY
脚本的意思是:先关闭屏幕回显,即你输入啥屏幕也不显示了;然后提示输出密码;验证密码是否正确给予反馈;打开回显;恢复终端设置。
看看效果哈:
- [root@localnode3 test]# sh stty.sh
- Please input passwd:
- Sorry
- [root@localnode3 test]# sh stty.sh
- Please input passwd:
- Welcome root
- [root@localnode3 test]#
挺有意思吧!
有了对 stty 的了解后,回头我们看看 spark-shell 脚本,就清晰明了了。
- saved_stty=$(stty -g 2>/dev/null)
首先保存了当前的终端配置。
- if [[ ! $? ]]; then
- saved_stty=""
- fi
如果收到退出命令,就恢复 stty 状态。
然后调用 main 方法,并传递所有的参数
, 最后根据返回状态,判断是直接终端退出还是恢复之前的终端界面。
- main "$@"
回头再看看 main 方法就容易理解了:
- function main() {
- if $cygwin; then
- stty -icanon min 1 -echo > /dev/null 2>&1
- export SPARK_SUBMIT_OPTS="$SPARK_SUBMIT_OPTS -Djline.terminal=unix"
- "${SPARK_HOME}"/bin/spark-submit --class org.apache.spark.repl.Main --name "Spark shell" "$@"
- stty icanon echo > /dev/null 2>&1
- else
- export SPARK_SUBMIT_OPTS
- "${SPARK_HOME}"/bin/spark-submit --class org.apache.spark.repl.Main --name "Spark shell" "$@"
- fi
- }
如果是 cygwin,先关闭 echo 回显,设置读操作最少 1 个字符。然后启动 spark-submit 执行
类,并设置应用的名字,传递参数。执行完成后,再开启 echo 回显。
- org.apache.spark.repl.Main
来源: http://www.cnblogs.com/xing901022/p/6415289.html