本文当为学习《Linux程序设计》一书学习笔记。文章中连接参考如有侵权请联删
shell脚本编程
在调用C语言编译器的时候,可以使用-I 标志包含保存在子目录或非标准位置中的头文件。
$ gcc -I/usr/openwin/include fred.c
指示编译器不仅在标准位置,也在命令给出目录中查找程序fred.c中爆仓就的头文件。
使用grep命令搜索目录下包含指定字段的文件
$grep EXIT_ *.h
在当前目录下搜索以.h结尾且包含EXIT_的文件。
C语言编译器默认情况下只搜索标准C语言库,库文件需要遵守特定的命名规范并且需要在命令行中明确指定。如果只是将库文件放在标准库目录下不能被编译器搜索到。库文件以lib开始命名,根据类型添加字母,以.a结尾的是静态连接库,以.so结尾的是动态连接库。
g
c
c
−
c
∗
.
c
编
译
当
前
文
件
夹
下
所
有
源
文
件
,
−
c
阻
止
编
译
器
创
建
一
个
完
整
的
程
序
。
L
i
n
u
x
中
创
建
静
态
库
文
件
1
、
编
写
包
含
函
数
的
头
文
件
2
、
使
用
gcc -c *.c 编译当前文件夹下所有源文件,-c阻止编译器创建一个完整的程序。 Linux中创建静态库文件 1、 编写包含函数的头文件 2、 使用
gcc−c∗.c编译当前文件夹下所有源文件,−c阻止编译器创建一个完整的程序。Linux中创建静态库文件1、编写包含函数的头文件2、使用gcc -c *.c 编译源文件
3、 使用
a
r
c
r
v
l
i
b
f
o
o
.
a
∗
.
o
将
编
译
后
的
文
件
归
档
;
4
、
为
函
数
库
生
成
内
容
表
ar crv libfoo.a *.o 将编译后的文件归档; 4、 为函数库生成内容表
arcrvlibfoo.a∗.o将编译后的文件归档;4、为函数库生成内容表ranlib *.a
5、 使用静态库文件$gcc -o myprogram myprogram.o libfoo.a或者使用
$gcc -o myprogram myprogram.o -L. lfoo使用-L指定函数库位置为当前位置。
使用命令查看目标文件、可执行文件和.a文件中包含的函数
n
m
∗
.
a
共
享
库
的
使
用
当
运
行
多
个
应
用
程
序
并
且
他
们
都
包
含
来
自
同
一
个
静
态
库
中
的
函
数
时
,
内
存
中
有
该
函
数
的
多
个
拷
贝
,
并
且
程
序
文
件
自
身
也
有
多
分
同
样
副
本
,
这
样
就
消
耗
大
量
内
存
资
源
。
使
用
静
态
连
接
时
,
程
序
本
身
不
包
含
函
数
代
码
,
而
是
引
用
运
行
时
可
访
问
的
共
享
代
码
。
当
应
用
程
序
被
加
载
到
内
存
中
,
函
数
引
用
被
解
析
并
产
生
对
共
享
库
的
调
用
。
查
看
应
用
程
序
需
要
的
共
享
库
nm *.a 共享库的使用 当运行多个应用程序并且他们都包含来自同一个静态库中的函数时,内存中有该函数的多个拷贝,并且程序文件自身也有多分同样副本,这样就消耗大量内存资源。使用静态连接时,程序本身不包含函数代码,而是引用运行时可访问的共享代码。当应用程序被加载到内存中,函数引用被解析并产生对共享库的调用。 查看应用程序需要的共享库
nm∗.a共享库的使用当运行多个应用程序并且他们都包含来自同一个静态库中的函数时,内存中有该函数的多个拷贝,并且程序文件自身也有多分同样副本,这样就消耗大量内存资源。使用静态连接时,程序本身不包含函数代码,而是引用运行时可访问的共享代码。当应用程序被加载到内存中,函数引用被解析并产生对共享库的调用。查看应用程序需要的共享库ldd myprogram
使用ar创建归档文件
$ ar crv libfoo.a bill.o fred.o
使用man命令访问在线手册,使用info访问在线文档系统。
查看gcc命令在线手册
$man gcc 使用空格翻页,使用回车键换行,按键q退出。
获得更多gcc信息使用info查看gcc命令
$info gcc
【问题:如何使用man和info,以及显示的文档结构,如何根据文档使用指令?】
Shell编程
bash在./bin/bash
2.4 管道和重定向
重定向输出
每个应用程序的输入被规定为文件标识符为0的标准输入,输出被规定为文件标识符为1的标准输出,如果应用程序是输出异常(错误)则输出到文件标识符为2的标准错误输出。可以重定向应用程序输出输出,将本来默认输出到标准输出的内容输出到其他文件中。
输出重定向$ ls -l > isoutput.txt
如果输出文件已经存在,内容被覆盖。
l
s
−
l
>
>
l
s
o
u
t
p
u
t
.
t
x
t
追
加
方
式
输
出
到
重
定
向
文
件
中
。
标
准
错
误
输
出
ls -l >> lsoutput.txt 追加方式输出到重定向文件中。 标准错误输出
ls−l>>lsoutput.txt追加方式输出到重定向文件中。标准错误输出ls -l 2> lserror.txt
将文件描述符放在重定向符号前表示将内容输出到指定文件。应用程序执行过程中出现错误情况会将错误内容输出到标准错误输出中,并且打印在屏幕上。使用标准错误输出重定向可以防止错误信息打印在屏幕上。
将应用程序输出重定向到不同文件中
$ls -l > lsoutput.txt 2>lserror.txt
$ls -l >lsoutput.txt 2>$1
将应用程序标准输出和错误输出重定向到同一文件中,注意顺序。
输出重定向
使用more程序显示指定文件(more程序接受文件名作为参数,此处只是示例)
$more < lsoutput.txt
2.4.3 管道
使用管道连接多个应用程序,连接的程序可以同时运行,并且随着数据流在程序之间的传递可以自动的协调。
如果有一系列命令需要执行,相应的输出文件是在这一组命令被创建的同时立刻创建或写入的,所以不要在命令流中重复使用相同的文件名。
2.5 作为程序设计语言的shell
使用*匹配字符串,使用[set]匹配符合条件的一个字符,使用[^set]匹配相反的字符集。
Shell程序编写
#注释当前行
#! 用于告诉系统后面的字符串是执行该文件的shell程序,使用绝对路径指明应用程序位置。
在shell进本应用程序中需要使用exit 生成返回码。
Shell脚本文件没有后缀名,使用file检查文件类型,从而知道当前文件是否是脚本文件。
把脚本设置成可执行
调用脚本文程序有两种方法:/bin/sh first或者更改脚本文件属性为可执行chmod +x fisrt,第二种方法执行shell脚本的时候需要注意使用./myscript方式。
更改PATH环境变量
PATH=$PATH:. 将当前目录添加。或者编辑bash_profile文件。
编写shell程序
shell命令大全 http://www.runoob.com/linux/linux-command-manual.html
Shell脚本不需要声明变量,在使用时候以字符串数据格式创建变量,数值也是以字符串形式存储(赋值给变量的数据是字符串类型),在需要时候转换成对应数值类型。为变量赋值直接使用变量名.使用“
变
量
名
”
形
式
访
问
变
量
内
容
。
使
用
=
给
变
量
赋
值
,
运
算
符
两
边
不
能
有
空
格
,
赋
值
内
容
使
用
双
引
号
包
含
起
来
(
如
果
赋
值
的
内
容
有
空
格
)
。
可
以
使
用
r
e
a
d
命
令
读
取
用
户
输
入
数
据
作
为
变
量
值
。
单
引
号
和
双
引
号
区
别
‘
变量名”形式访问变量内容。使用=给变量赋值,运算符两边不能有空格,赋值内容使用双引号包含起来(如果赋值的内容有空格)。 可以使用read命令读取用户输入数据作为变量值。 单引号和双引号区别 ‘
变量名”形式访问变量内容。使用=给变量赋值,运算符两边不能有空格,赋值内容使用双引号包含起来(如果赋值的内容有空格)。可以使用read命令读取用户输入数据作为变量值。单引号和双引号区别‘var’ 在程序运行中将其中作为字符串(不包括单引号),”$VAR”程序运行中将VAR值替换双引号。
2 环境变量
3 参数变量
脚本程序在调用时候带有参数,这些参数将赋值给参数变量,区别于环境变量。
不管是参数变量或者是环境变量,在脚本程序中都可以是使用,只不过是含义不同而已。
2.6.2 条件
条件指令使用
http://www.runoob.com/linux/linux-shell-test.html
使用test命令或者[命令结合参数进行判断,[前后要留有空格。
test 可以实现字符串比较、算术比较与文件有关的条件测试。
检查系统中是否有一个指定名称的外部命令,可以尝试使用which test这样的命令来检查执行了那个命令。
$ if test -f myfile.txt ; then
…
fi
条件判断
注意:在变量使用的时候需要加上引号,否则当变量值为空的时候程序会出错。
echo自带换行符,使用echo -n “字符串”去掉换行符
for 语句
1、 使用固定字符串
in后面的是字符串。
如果将固定字符串用双引号包括起来,则被看成一个字符串,结果将一次性输出字符串。
2、 使用通配符扩展for循环
注意shell脚本程序在运行的时候要考虑当前运行条件,包括所在目录比如上述代码。
while语句
条件为真执行语句,否则执行循环体后面的语句。
条件判断!=前后必须有空格,否则判断失败。
until
直到判断条件为真,否则执行循环体。
case
注意;;符号前没有空格,使用通配符处理所有没有匹配上的情况。
合并匹配模式
注意:通配符在引号中不起作用。
执行多条语句
注意esac语句前的两个分号,在case中执行多个语句,以及模式的组合。
命令列表(多个判断条件组合)
AND和OR
逻辑与
逻辑或
条件判断语句只要有一个为真在结束判断否则顺序判断。
第一条语句为true则返回,否则执行第二条语句,如果第二条语句为false执行三条语句。注意逻辑判断结合顺序,可以使用括号来强制求值顺序。
使用符号{}将多个语句包括起来用在逻辑判断语句中,该语句块将作为一个语句。
2.6.4 函数
调用函数与子shell脚本程序有优势在于使用函数效率更高。
shell脚本程序中函数的定义
当一个函数被调用的时候,脚本程序的位置参数($* $@ $# $1 $2 $3等等)将被替换成函数的参数。函数必须在调用前被申明,一般将函数放在shell脚本程序的顶部。函数可以使用return指定返回值,如果没有指定,函数返回值为函数体内最后一条语句执行返回码。函数可以访问定义在函数体外的全局变量,也可以使用local关键字定义局部变量。局部变量和全局变量如果同名,全局变量会被代替,作用于在局部变量作用域范围内。调用函数时候只需要函数名,不要添加括号。函数调用时候可以为函数传参,代码中直接将参数以双引号形式放在函数名末尾。
2.6.5 命令
分为内部命令和外部命令:区别在于是否是shell内部实现
1、 使用break打破while、for或until循环。
2、 命令:相当于true,可以与while搭配实现死循环。
3、 continue跳出当前循环。
4、 echo删除换行符,如果脚本需要兼容UNIX系统使用printf命令,如果兼容Linux和bash使用echo-n命令。
5、 第二段代码输出10
eval可以看成一个$,给出一个变量的变量值。
6、 exec命令,脚本中使用该命令会将当前的shell替换成不同的程序P64,或者用来修改当前文件描述符。exec wall “Thanks for all the fish”exec命令后的语句不会被执行,因为当前的shell已经替换成了wall。exec 3< afile 打开文件描述符3并且从afile中读取数据。
7、 exit n返回值,0表示true,否则shell脚本程序将最后一条语句作为退出码。
8、 export命令将作为其参数的变量导出到子shell,从当前shell生成的子shell无法访问父shell的变量。该命令将传递的参数创建为环境变量,该变量可以被当前shell程序调用的其他子shell程序使用。(export命令导出的变量可以被当前shell使用以及当前shell中调用的子shell使用以及子孙shell使用。)export将自己的参数创建为一个环境变量,而这个环境变量可以被当前shell调用的子孙shell看见。
9、 expr将传递的参数作为表达式来求值,
printf指令
return命令
标准格式是”return 退出码”,如果没有指定退出码,默认为返回最后一条命令的退出码。
set命令
为shell设置参数变量(所谓参数变量就是在命令行传递给shell命令的字符串)
上述代码在Ubuntu上运行后无法正常输出,如下图
每个$(date)命令结果部分都执行了相应输出指令,并且无法正常显示年、月
shift指令
将脚本程序的参数变量整体向左移动,$1被丢弃,
0
不
变
,
如
果
s
h
i
f
t
后
面
指
定
了
整
数
值
则
表
明
移
动
的
次
数
。
相
应
的
0不变,如果shift后面指定了整数值则表明移动的次数。相应的
0不变,如果shift后面指定了整数值则表明移动的次数。相应的*、
@
、
@、
@、#也要做相应的更改。
trap命令
在shell脚本程序中trap可以看成一个函数声明,只有在当前执行的shell脚本应用程序接受到指定信号后调用trap指定的处理方式,并且只调用一次。如果没有command参数,则执行默认操作。
unset命令
将变量从环境中删除,除了只读变量(比如IFS)
find命令
格式:(P70 17)
1、 方括号对应的值可以有多个
2、 options和tests和actions都是以-开始的参数,只是每个都不同,所以在使用find命令的时只需要注意顺序就行了。
使用括号将测试条件括起来强制测试和操作符的优先级,由于括号在shell有特别意义,所以,需要用斜线。使用操作符-o来组合测试,该操作符可以换成长格式。注意使用双引号将_*包含。
grep命令
该命令可以用于在文件中搜索字符串。一种常用的做法是就grep传递给find命令的 -exec参数。
正则表达式
详情见P74
算数扩展
(
.
.
.
)
将
命
令
替
换
进
括
号
中
,
得
到
命
令
的
输
出
结
果
。
可
以
将
该
输
出
结
果
给
变
量
赋
值
。
使
用
(...)将命令替换进括号中,得到命令的输出结果。可以将该输出结果给变量赋值。 使用
(...)将命令替换进括号中,得到命令的输出结果。可以将该输出结果给变量赋值。使用((…))将两个括号里的字符串作为算数运算,区别于$()括号里的内容为命令的执行和获取输出。
1、算数扩展
2、参数扩展
P77
把参数值替换进字符串中。
每次循环中将i当前值替换$(i),从而更改每次执行变量。
将当前目录下.gif转换成jpg格式文件。
here文档
格式
重定向符<<特殊字符序列,注意特殊字符序列是和重定向符紧紧相连的,特殊字符序列的作用是标志here文档的开始和结束。
在shell脚本程序中可以调用交互式程序,并且使用here文档为交互式程序提供预先定义好的指令。
在shell脚本程序中使用ed命令编辑文件a_text_file然后使用here文档与ed命令交互式操作。该命令首先执行ed命令,然后向ed程序传入指令,指令的内容便是here文档的内容,在here文档中出现$符号的时候需要将其转意,否则当前的shell将其扩展为变量值。shell首先将$传递为$,再由ed对其进行编辑。