《Linux程序设计》笔记(二)shell程序设计
1. 进程树形显示
ps -e f
2. 重定向
>
覆盖文件
>>
附加至文件
1>
标准输出
2>
标准错误输出
0
代表一个程序的标准输入
3. 程序可以在当前目录被查找
执行PATH=$PATH:.
或者添加这条命令到.bash_profile
,退出登录后再重新登录
4. 变量
用户输入赋值:read var1
改变命令提示符:echo "PS1='\u: \W$ '" >> ~/.bashrc
引号:如果把一个\(变量表达式放在双引号中,程序执行到这一行时就会把变量替换为它的值;如果你把它放在单引号中,就不会发生替换现象。还可以在\)字符前面加上一个\字符以取消它的特殊含义。
环境变量:
环境变量 | 说明 |
---|---|
$HOME | 当前用户的HOME目录 |
$PATH | 以冒号分隔的用来搜索命令的目录列表 |
$PS1 | 命令提示符,通常是\(字符,但在bash中,可以使用一些复杂的值。例如,字符串[\u@\h \W]\)就是一个流行的默认值,它给出用户名、机器名和当前目录名 |
$PS2 | 二级提示符,用来提示后续的输入 |
$IFS | 输入域分隔符 |
$0 | shell脚本的名字 |
$# | 传递给脚本的参数个数 |
$$ | shell脚本的进程号,脚本程序通常会用它来生成一个唯一的临时文件,如/tmp/tmpfile_$$ |
参数变量:
参数变量 | 说明 |
---|---|
$1, $2, ... | 脚本程序的参数 |
$* | 在一个脚本变量中列出所有的参数,各个参数之间用环境变量IFS中的第一个分隔符分开。 |
$@ | 它是$*的一种精巧的变体,它不使用IFS环境变量 |
5. 条件
test或[命令:布尔判断命令。
可使用的条件类型归为3类:字符串比较、算数比较、与文件有关的条件测试。
具体使用方法参照:man test
Exmaple:
if test -f fred.c
then
...
fi
还可以写成这样:
if [ -f fred.c ]
then
...
fi
6. 控制结构
if语句
elif语句
echo -n
可以去除尾部的换行符。(password.sh
)
for循环
#!/bin/sh
for foo in bar fud 43; do
echo $foo
done
exit
使用通配符扩展for循环
#!/bin/sh
for file in $(ls f*); do
lpr $file
done
exit 0
while语句
用法见password.sh
until语句
与while语句相反
until condition; do
statements
done
case语句
case variable in
pattern [ | pattern] ...) statements;;
pattern [ | pattern] ...) statements;;
...
esac
详情见case.sh
命令列表
AND列表 | OR列表 |
---|---|
&& | || |
语句块
如果想在某些只允许使用单个语句的地方(比如AND或OR列表中)使用多条语句,可以把它们括在{}中来构造一个语句块。
get_confirm && {
grep -v "$cdcatnum" $tracks_file > $temp_file
cat $temp_file > $tracks_file
echo
add_record_tracks
}
函数
foo() {
echo "Function foo is executing"
}
echo "script starting"
foo
echo "script ended"
exit 0
详细用法见my_name.sh
命令
-
break
命令:跳出for、while、until循环。 -
:
命令:空命令,在条件逻辑中也相当于true的别名,内置命令。while :
实现了一个无限循环。if [-f fred.sh ]; then : else echo file fred did not exist fi
-
continue
命令:跳到for、while、until的下一次循环。1. .
命令:用于在当前shell中执行命令。. ./shell_scripte
source命令和点命令在执行脚本程序中列出的命令时,使用的是调用该脚本程序的同一个shell。
-
echo
命令:输出结尾带有换行符的字符串。 -
eval
命令:对参数进行求值。有点像一个额外的$,它给出一个变量的值的值。
foo=10
x=foo
eval y='\('\)x
echo $y
```
-
exec
命令:1.将当前shell替换为一个不同的程序; 2.修改当前文件描述符。 -
exit n
命令:退出码0表示成功,退出1~125是脚本程序可以使用的错误代码。其余数字具有保留含义。退出码 说明 123 文件不可执行 127 命令未找到 128及以上 出现一个信号 -
export
命令:将作为它参数的变量导出到子shell中,并使之在子shell中有效。 -
expr
命令:将它的参数当作一个表达式来求值。x=\
expr \(x + 1\`` 或 `x=\)(expr $x + 1)`在较新的脚本程序中,
expr
命令通常会被替换为更有效的$((...))
语法。 -
printf
命令:格式化输出。不支持浮点数。更详细介绍可以参考printf在线手册的第一部分(man 1 printf
)。字符转换限定符 说明 d 输出一个十进制数字 c 输出一个字符 s 输出一个字符串 % 输出一个%字符 printf "%s\n" hello
printf "%s %d\t%s" "Hi There" 15 people
-
return
命令:函数返回。 -
set
命令:为shell设置参数变量。#!/bin/sh echo the date is $(date) set $(date) echo The month is $2 exit 0
这个程序把date命令的输出设置为参数列表,然后通过位置参数$2获得月份。
-
shift
命令:把所有参数变量左移一个位置,使$2变成$1,原来$1的值将被丢弃,$0不变。shift命令后面可以指定左移位数。#!/bin/sh while [ "$1" != "" ]; do echo "$1" shift done exit 0
-
trap
命令:用于指定在接收到信号后将要采取的行动。trap command signal
第一个参数是接收到指定信号时将要采取的行动,第二个参数是要处理的信号名。
信号 说明 HUP(1) 挂起,通常因终端掉线或用户退出而引发 INT(2) 中断,通常因按下Ctrl+C组合键而引发 QUIT(3) 退出,通常因按下Ctrl+\组合键而引发 ABRT(6) 中止,通常因某些严重的执行错误而引发 ALRM(14) 报警,通常用来处理超时 TERM(15) 终止,通常在系统关机时发送 具体使用见
trap/sh
-
unset
命令:从环境中删除变量或函数。这个命令不能删除shell本身定义的只读变量(如IFS)。foo = "Hello World" echo $foo unset foo echo $foo
-
find
命令:用于搜索文件的命令。find [path] [options] [tests] [actions]
find . -newer while2 -type f -print
在当前目录下搜索比文件while2要新的文件 -
grep
命令:通用正则表达式解析器。选项 含义 -c 输出匹配行的数目,而不是输出匹配的行 -E 启用扩展式 -h 取消每个输出行的普通前缀,即匹配查询模式8的文件名 -i 忽略大小写 -l 只列出包含匹配行的文件名,而不输出真正的匹配行 -v 对匹配模式取反,即搜索不匹配行而不是匹配行 grep -c in words.txt words2.txt
在两个不同的文件中计算匹配行的数目。 -
正则表达式
常用特殊符号 含义 ^ 指向一行的开头 $ 指向一行的结尾 . 任意单个字符 [] 方括号内包含一个字符范围,其中任何一个字符都可以被匹配。例如自负范围a~e,或在字符范围前面加上^符号表示使用反向字符范围,即不匹配指定范围内的字符 选项 含义 ? 匹配是可选的,但是最多匹配一次 * 必须匹配0次或多次 + 必须匹配1次或多次 必须匹配n次 必须匹配n次或n次以上 匹配次数在n到m之间,包括n和m
命令的执行
$(command)
语法用来捕获command命令的执行结果。也就是说,执行一条命令,并把该命令的输出放到一个变量中。例如:
echo The current directory is $PWD
echo The current users are $(who)
whoisthere=$(who)
echo $whoisthere
exit
-
算数扩展
#!/bin/sh x=0 while [ "$x" -ne 10 ]; do echo $x x=$(($x+1)) done exit 0
-
参数扩展
#!/bin/sh for i in 1 2 do cat ${i}_tmp done
在每次循环中,变量i的值替换了$(i),从而给出正确的文件名。
参数扩展 说明 $ 如果param为空,就把它设置为default的值 $ 给出param的长度 $ 从param的尾部开始删除与word匹配的最小部分,然后返回剩余部分 $ 从param的尾部开始删除与word匹配的最长部分,然后返回剩余部分 $ 从param的头部开始删除与word匹配的最小部分,然后返回剩余部分 $ 从param的头部开始删除与word匹配的最长部分,然后返回剩余部分 比如:
lor@lor-vm:~$ w=nidaye lor@lor-vm:~$ echo ${w%%y} nidaye lor@lor-vm:~$ echo ${w%%e} niday lor@lor-vm:~$ echo ${w%%*} lor@lor-vm:~$ echo ${w%*} nidaye lor@lor-vm:~$ echo ${w%e} niday lor@lor-vm:~$ echo www${w%%e} wwwniday
here
文档
在shell脚本程序中向一条命令传递输入得一种特殊方法是使用here
文档。它允许一条命令在获得输入数据时就好像是在读取一个文件或键盘一样,而实际上是从脚本程序中得到的输入数据。
#!/bin/sh
cat <<melo
hello
world
melo
cat <<!this-is-here-document!
this
is
here
document
!
!this-is-here-document!
------------------------------------
运行结果:
lor@lor-vm:~$ bash ./here
hello
world
this
is
here
document
!
调试脚本程序
命令行选项 | set选项 | 说明 |
---|---|---|
sh -n <script> | set -o noexec set -n |
只检查语法错误,不执行命令 |
sh -v <script> | set -o verbose set -v |
在执行命令之前回显它们 |
sh -x <script> | set -o xtrace set -x |
在处理完命令之后回显它们 |
sh -u <script> | set -o nounset set -u |
如果使用了未定义的变量,就给出出错信息 |
使用下面的命令来启用xtrace选项:
set -o xtrace
再用下面的命令来关闭xtrace选项:
set +o xtrace
在shell中,你还可以通过捕获EXIT信号,从而在脚本程序退出时查看到程序的状态。
`trap 'echo Exiting: critical variable = $critiacal_variable' EXIT
7. 迈向图形化:dialog工具
第一个程序:
dialog --msgbox "Hello World" 9 18
更复杂的程序:
dialog --title "Confirm" --yesno "Are you willing to take part?" 9 18
if [ $? != 0 ]; then
dialog --infobox "Thank you anyway" 5 20
sleep 2
dialog --clear
exit 0
fi
使用一个输入框来询问用户的姓名,将它保存到变量Q_NAME中:
dialog --title "Questionnaire" --input "Please enter your name" 9 30 2>_1.txt
Q_NAME=$(cat _1.txt)
重定向标准错误流2到临时文件_1.txt,然后再将它放到变量Q_NAME中。
8. 综合应用
CD数据库应用程序。对每张CD唱片保存以下消息:
- CD唱片的目录编号
- 标题
- 曲目类型
- 作曲家或艺术家
对曲目,我们只保存两条信息:
- 曲目编号
- 曲名
标题文件:
目录编号 | 标题 | 曲目类型 | 作曲家 |
---|---|---|---|
CD123 | Cool sax | 爵士 | Bix |
CD234 | Classic violin | 古典 | Bach |
CD345 | Hits99 | 流行 | Various |
曲目文件:
目录编号 | 曲目编号 | 曲名 |
---|---|---|
CD123 | 1 | Some jazz |
CD123 | 2 | More jazz |
CD234 | 1 | Sonata in D minor |
CD345 | 1 | Dizzy |
使用CSV文件保存数据。
代码见CDDB.sh