Lec2-Shell Programming
1. What is Shell?
Shell:
A command interpreter and programming environment
用户和操作系统之间的接口
作为核外程序而存在
1.1. Shell: 用户和操作系统之间的接口
1.2. Shell:作为核外程序而存在
1.3. 各种不同的Shell
shell 名称
描述
位置
ash
一个小的shell
/bin/ash
ash.static
一个不依靠软件库的ash版本
/bin/ash.static
bsh
ash的一个符号链接
/bin/bsh
bash
“Bourne Again Shell”。Linux中的主角,来自GNU项目
/bin/bash
sh
bash的一个符号链接
/bin/sh
csh
C shell, tcsh的一个符号链接
/bin/csh
tcsh
和csh兼容的shell
/bin/tcsh
ksh
Korn Shell
/bin/ksh
1.4. Shell 的双重角色
命令解释程序
Linux的开机启动过程;进程树
Shell的工作步骤
打印提示符;得到命令行;解析命令;查找文件;准备参数;执行命令
独立的程序设计语言解释器
KISS (Keep It Small and Stupid)
Reusable tools
Redirection and pipe
1.5. UNIX的哲学(示例)
重定向
使用"echo"创建文件吗?
管道
获取目录中文件的数量?
仅显示子目录?
ar t /usr/lib/libc.a | grep printf | pr -4 -t(?)
2. 脚本
2.1. 脚本是能在命令行直接输入的
但仅会执行一次
2.2. 编写脚本文件
脚本文件
注释
退出码(exit code)
1 2 3 4 5 6 7 8 #!/bin/bash for file in *; do if grep –l POSIX $file ; then more $file fi done exit 0
2.3. 执行脚本文件
Method 1: sh script_file
Method 2:
chmod +x script_file (chown, chgrp optionally)
./script_file
Method 3:
source script_file, or
./script_file
2.4. 用户环境
.bash_profile
, .bash_logout
, .bashrc files
.bash_profile
: 用户登录时被读取,其中包含的命令被bash执行
.bashrc
: 启动一个新的shell时读取并执行
.bash_logout
: 登录退出时读取执行
Alias
alias/unaliascommand
环境变量
export command
export, env & set command
2.5. 变量
用户变量
环境变量
参数变量和内部变量
2.5.1. 用户变量
用户变量:
用户在shell脚本里定义的变量
变量的赋值和使用
var=value
echo $var
read命令
用法:read var
或read
REPLY variable
引号的用法
双引号,单引号
转义符""
2.5.2. read 用法
1 2 3 4 5 #! /bin/bash echo -n "Enter your name: " read name echo "hello $name , welcome to my program" exit 0
1 2 3 4 5 read -p "Enter your name:" name read -p "Enter a number:" numberecho $number exit 0
1 2 3 4 5 6 7 8 9 #! /bin/bash if read -t 5 -p "please enter your name:" namethen echo "hello $name , welcome to my script" else echo "sorry, too slow" fi exit 0
1 2 3 4 5 6 7 8 9 10 11 12 #! /bin/bash read -n1 -p "DO you want to continue[ Y/N] ?" answercase $answer in Y|y) echo "fine, continue" ;; N|n) echo "ok, good bye" ;; *) echo "error choice" ;;esac exit 0
1 2 3 4 5 #! /bin/bash read -s -p "Enter your password: " passecho "your password is $pass " exit 0
1 2 3 4 5 6 7 8 9 #! /bin/bash count=1cat viewFile.sh| while read linedo echo "Scount:$line " count=$(($count + 1 ))done echo "Total Count:$count " exit 0
2.6. 引号的用法
单引号内的所有字符都保持它本身字符的意思,而不会被bash进行解释,例如,$
就是$
本身而不再是bash的变量引用符;\就是\本身而不再是bash的转义字符。
除了$、``(不是单引号)和\外,双引号内的所有字符将保持字符本身的含义而不被bash解释
2.7. 环境变量
环境变量:Shell环境提供的变量。通常使用大写字母做名字
环境变量
说明
$HOME
当前用户的登陆目录
$PATH
以冒号分隔的用来搜索命令的目录清单
$PS1
命令行提示符,通常是”$”字符
$PS2
辅助提示符,用来提示后续输入,通常是”>”字符
$IFS
输入区分隔符。当shell读取输入数据时会把一组字符看成是单词之间的分隔符,通常是空格、制表符、换行符等。
env:显示全部环境变量
set:设置环境变量
1 2 sed 's/ A / B /g' code1.cpp 正则表达式
2.8. 参数变量和内部变量
调用脚本程序时如果带有参数,对应的参数和额外产生的一些变量。
环境变量
说明
$#
传递到脚本程序的参数个数
$0
脚本程序的名字
$1
, $2
, …
脚本程序的参数
$*
一个全体参数组成的清单,它是一个独立的变量,各个参数之间用环境变量IFS中的第一个字符分隔开
$@
“$*”的一种变体,它不使用IFS环境变量。
2.9. 条件测试
退出码
test命令:test expression
或 [ expression ]
test命令支持的条件测试
字符串比较
算术比较
与文件有关的条件测试
逻辑操作
2.10. 字符串比较
字符串比较
结果
str1 = str2
两个字符串相同则结果为真
str1!=str2
两个字符串不相同则结果为真
-z str
字符串为空则结果为真
-n str
字符串不为空则结果为真
2.11. 算术比较
算术比较
结果
expr1 –eq expr2
两个表达式相等则结果为真
expr1 –ne expr2
两个表达式不等则结果为真
expr1 –gt expr2
expr1 大于expr2 则结果为真
expr1 –ge expr2
expr1 大于或等于expr2 则结果为真
expr1 –lt expr2
expr1 小于expr2 则结果为真
expr1 –le expr2
expr1 小于或等于expr2 则结果为真
2.12. 与文件有关的条件测试
文件条件测试
结果
-e file
文件存在则结果为真
-d file
文件是一个子目录则结果为真
-f file
文件是一个普通文件则结果为真
-s file
文件的长度不为零则结果为真
-r file
文件可读则结果为真
-w file
文件可写则结果为真
-x file
文件可执行则结果为真
2.13. 逻辑操作
逻辑操作
结果
! expr
逻辑表达式求反
expr1 –a expr2
两个逻辑表达式“And”(“与”)
expr1 –o expr2
两个逻辑表达式“Or”(“或”)
2.14. 条件操作
2.14.1. if语句
形式
1 2 3 4 5 6 7 8 9 10 if [ expression ] then statements elif [ expression ] then statements elif … else statements fi
紧凑形式:;
同一行上多个命令的分隔符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 if [ -f ~/.bashrc ]; then . ~/.bashrcfi echo "Is this morning? Please answer yes or no." read answerif [ "$answer " = "yes" ]; then echo "Good morning" elif [ "$answer " = "no" ]; then echo "Good afternoon" else echo "Sorry, $answer not recognized. Enter yes or no" exit 1fi exit 0
2.14.2. case语句
形式
1 2 3 4 5 case str in str1 | str2) statements;; str3 | str4) statements;; *) statements;;esac
例子Eg
1 2 3 4 5 6 7 8 9 #!/bin/sh echo "Is this morning? Please answer yes or no." read answercase "$answer " in yes | y | Yes | YES) echo "Good morning!" ;; no | n | No | NO) echo "Good afternoon!" ;; *) echo "Sorry, answer not recognized." ;;esac exit 0
2.15. 重复语句
2.15.1. for语句
形式
1 2 3 4 for var in listdo statementsdone
适用于对一系列字符串循环处理
1 2 3 4 5 #!/bin/sh for file in $(ls f*.sh); do lpr $file done exit 0
2.15.2. while语句
形式
1 2 3 4 while conditiondo statementsdone
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 quit=nwhile [ "$quit " != "y" ]; do read menu_choice case "$menu_choice " in a) do_something;; b) do_anotherthing;; … q|Q) quit=y;; *) echo "Sorry, choice not recognized." ;; esac done a=0while [ "$a " -le "$LIMIT " ]do a=$(($a +1 )) if [ "$a " -gt 2 ] then break fi echo -n "$a " done
2.15.3. until语句
形式
1 2 3 4 until conditiondo statementsdone
Not recommended (while statement is preferred)
2.15.4. select语句
形式
1 2 3 4 select item in itemlistdo statementsdone
作用:生成菜单列表
Eg. 一个简单的菜单选择程序
1 2 3 4 5 6 7 8 9 10 #!/bin/sh clear select item in Continue Finishdo case "$item " in Continue) ;; Finish) break ;; *) echo "Wrong choice! Please select again!" ;; esac done
2.16. 补充read
1 2 3 4 5 6 7 8 9 10 11 read [-rs] [-a ARRAY] [-d delim] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [var_name1 var_name2 ...] 选项说明: -a:将分裂后的字段依次存储到指定的数组中,存储的起始位置从数组的index=0开始。 -d:指定读取行的结束符号。默认结束符号为换行符。 -n:限制读取N个字符就自动结束读取,如果没有读满N个字符就按下回车或遇到换行符,则也会结束读取。 -N:严格要求读满N个字符才自动结束读取,即使中途按下了回车或遇到了换行符也不结束。其中换行符或回车算一个字符。 -p:给出提示符。默认不支持"\n"换行,要换行需要特殊处理,见下文示例。例如,"-p 请输入密码:" -r:禁止反斜线的转义功能。这意味着"\"会变成文本的一部分。 -s:静默模式。输入的内容不会回显在屏幕上。 -t:给出超时时间,在达到超时时间时,read退出并返回错误。也就是说不会读取任何内容,即使已经输入了一部分。
如果输入的是纯数值的话,那么比较的时候,可以使用算数比较,也可以使用字符串比较。
2.17. 命令表和语句块
命令表(命令组合)
语句块
2.17.1. 命令表
命令组合
分号串联:command1 ; command2 ;
条件组合
AND命令表,格式:statement1 && statement2 && statement3
OR命令表,格式:statement1 || statement2 || statement3 || …
2.17.2. 语句块
形式
1 2 3 4 5 6 7 8 { statement1 statement2 } { statement1; statement2 ;}
2.17.3. 函数
形式
局部变量:local关键字
函数的调用:func para1 para2
返回值:return
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 yesno () { msg="$1 " def="$2 " while true ; do echo " " echo "$msg " read answer if [ -n "$answer " ]; then case "$answer " in y|Y|yes |YES) return 0 ;; n|N|no|NO) return 1 ;; *) echo " " echo "ERROR: Invalid response, expected \"yes\" or \"no\"." continue ;; esac else return $def fi done }if yesno "Continue installation? [n]" 1 ; then : else exit 1 f
2.18. 其他
杂项命令:break, continue, exit, return, export, set, unset, trap, ":", ".", …
捕获命令输出
算术扩展
参数扩展
即时文档
2.18.1. 杂项命令
break: 从for/while/until循环退出
continue: 跳到下一个循环继续执行
exit n: 以退出码"n"退出脚本运行
return: 函数返回
export: 将变量导出到shell,使之成为shell的环境变量
set: 为shell设置参数变量
unset: 从环境中删除变量或函数
trap: 指定在收到操作系统信号后执行的动作
“:”(冒号命令): 空命令
“.”(句点命令)或source: 在当前shell中执行命令
2.18.2. 捕获命令输出
语法
$(command)
`command`
举例
1 2 3 4 #!/bin/sh echo "The current directory is $PWD " echo "The current directory is $(pwd) " exit 0
2.18.3. 算术扩展
$(())扩展
1 2 3 4 5 6 7 #!/bin/sh x=0while [ "$x " –ne 10 ]; do echo $x x=$(($x +1 ))done exit 0
2.18.4. 参考扩展
问题:
批处理 1_tmp, 2_tmp, …
方法
1 2 3 4 5 6 7 #!/bin/sh i=0while [ "$i " –ne 10 ]; do touch "${i} _tmp" i=$(($i +1 ))done exit 0
2.18.5. 参数扩展更复杂的形式
2.18.6. 即时文档
在shell脚本中向一条命令传送输入数据
Example
1 2 3 4 #!/bin/bash cat >> file.txt << !CATINPUT! Hello, this is a here document. !CATINPUT!