490 likes | 654 Views
Linux 程序设计基础. 西安交通大学 李思 2004 年 8 月 25 日. 主要内容. Java 程序开发环境 C/C++ 程序设计基础 使用 gcc 编译程序 LinuxC 编程与 WindowsC 编程的主要区别 使用 gdb 调试程序 Make 和 Makefile 其它工具: Indent 和 CVS Shell 编程快速入门 Bash 脚本 正则表达式, Sed 和 awk. 1. Java 程序开发环境. JDK 的安装.
E N D
Linux程序设计基础 西安交通大学 李思 2004年8月25日
主要内容 • Java程序开发环境 • C/C++程序设计基础 • 使用gcc编译程序 • LinuxC编程与WindowsC编程的主要区别 • 使用gdb调试程序 • Make和Makefile • 其它工具:Indent和CVS • Shell编程快速入门 • Bash脚本 • 正则表达式,Sed和awk
JDK的安装 • 到sun.java.com下载jdk的安装文件:j2sdk-1_4_2_05-linux-i586.bin并把文件存放到/usr/local下 • #chmod +x j2sdk-xxxxxx.bin • #/usr/local/j2sdk-xxxxxx.bin • ln -s j2sdk1.4.2_04 java • 编辑/etc/profile,增加如下三行: • export JAVA_HOME=/usr/local/java/ • export CLASSPATH=.:/usr/local/java/lib/dt.jar:/usr/local/ java/lib/tools/jar • export PATH=/usr/local/java/bin:$PATH • 注意:上面命令中不能随意添加空格 • 退出,重新登陆
Hello World • #vi HelloWorld.java • public class HelloWorld • { • public static final void main( String args[] ) • { • System.out.println("Hello World"); • } • } • #javac HelloWorld.java • #java HelloWorld
其它开发工具 • Linux下常用的Java集成化开发环境有 • JBuilder(最新版为X) • Eclipse(最新版为3.0) • Eclipse安装提示 • 有motif和gtk两个版本,建议选gtk版 • 安装Eclipse之前必须先安装JDK或者JRE • 用unzip命令解开压缩包 • 运行方法:eclipse -vm /usr/local/java/bin/java -vmargs -Xmx256M
开发工具与开发环境 • 基本工具 • vi, emacs, gcc, g++, gdb • 图形界面调试工具DDD • 集成化开发环境 • Kylix、Kdevelop、Eclipse+CDT • 工程管理 • 版本控制:CVS • 条件编译:make
gcc/g++ • 用法: gcc[<options>] <input files> • 常用的选项: • -g:产生调试信息 (用于gdb调试) • -Wall:输出所有警告信息 • -D<sym>:在所有源代码中定义<sym> • -o <name>:指定输出文件名 • -c: 只编译成目标文件,不连接 • -I <dir_name>: 指定include的路径 • -l<lib_name>: 指定需要连接的库 • -S: 输出汇编语言文件 • -O: 对编译的结果进行优化 • Example: gcc -g –Wall –o hello hello.cpp
头文件 • 系统默认的头文件路径为: • /usr/include • 当头文件既不在源代码目录下,也不在默认目录下时,有两种办法指定其目录 • 在源文件中指定,例如:#include </usr/local/mysql/include> • 编译时通过-I参数指定,例如:gcc –o foo foo.c –I /usr/local/mysql/include • 一般在编写内核模块驱动程序时需要指定头文件路径
静态库文件的连接 • 静态库文件位于/usr/lib目录下,文件名为libname.a • 当使用到库函数时,应该把库函数连接到程序中去 • 例如:gcc -o foo.c -lm • 注意:-l的参数不是库文件名,而是库名 • 如果库不在/usr/lib下,应该采用-L参数指定其路径 • 例如: gcc -o foo foo.c -L /root –lmylib • 常用的静态库包括:数学库m,线程库pthread,动态加载库dl等
共享库(1) • 共享库的生成 • 使用-fPIC参数生成位置无关代码 • 使用-shared参数生成共享目标库 • 例如: gcc -fPIC -shared -o libfoo.so foo.c • 共享库的调用 • 使用dlopen函数打开共享库文件 • 使用dlsym取得共享函数的指针 • 使用共享函数指针调用共享函数 • 使用dlclose关闭共享库文件 • 编译方法:gcc -o foo foo.c -ldl
共享库(2) • 如果在dlopen函数中没有指定共享库文件的绝对路径,则按照一下顺序搜索 • 用户的LD_LIBRARY_PATH环境变量 • /etc/ld.so.cache中列出的路径 • /lib和/usr/lib • 注意:不要直接修改/etc/ld.so.cache • 应该修改/etc/ld.so.conf • 然后运行ldconfig以更新/etc/ld.so.cache • 使用ldd命令可以列出一个程序所依赖的共享库 • 例如: ldd /bin/ls
Linux IPC概述 • 进程间通信IPC是Linux编程与Windows编程最大的区别之一 • Linux下的进程间通信分为以下几类: • 信号:用于进程间的事件通知,如定时器等 • 管道:父子进程之间单向的通信机制 • 信号量:用于实现进程间的同步 • 消息队列:用于实现异步共享通信 • 共享内存:用于进程间共享数据 • UnixSocket:与BSD Socket类似,但效率高于后者
Make与Makefile • 当一个程序包含多个C语言源代码文件时,手工编译程序将会十分麻烦 • make实际上是工程(项目)管理程序,它可以根据makefile中定义的规则自动编译、安装程序 • makefile可以自己编写,但更多时候是由开发工具自动生成(autoscan, aclocal, autoconf, automake) • Make命令的格式 • make [-f <makefilename>] [<target>] • 如果不指定makefilename,默认为当前目录下的makefile或者Makefile • Target是Makefile中定义的目标,默认为第一个目标
Makefile的写法 • Makefile内部可分为两部分 • 变量定义: • <variable>=<string value> • 所有变量的默认值都源自于Shell变量 • 规则定义: • <目标>: <依赖><命令> • <目标>是指本条规则要生成的文件或达到的效果 • <依赖>是指执行本条规则所需要的文件或者条件,它可以是文件,也可以是其它目标 • <命令>是指本条规则的动作,Makefile中的第一个目标是默认的目标
Makefile实例 # Example Makefile CC=g++ CCOPTS=-g –Wall -DDEBUG foobar: foo.o bar.o $(CC) $(CCOPTS) –o foobar foo.o bar.o foo.o: foo.cpp foo.h $(CC) $(CCOPTS) –c foo.cpp bar.o: bar.cpp bar.h $(CC) $(CCOPTS) –c bar.cpp clean: rm foo.o bar.o foobar
Makefile的常用缩写 • $@ 代表该目标的全名 • $* 代表已经删除了后缀的目标名 • $< 代表该目标的第一个相关目标名 • 例如: prog: prog1.o prog2.o gcc prog1.o prog2.o -o $@ prog1.o: prog1.c lib.h gcc -c -I. -o $@ $< prog2.o: prog2.c gcc -c $*.c
GDB • GDB=GNU DeBugger • 它是一个文字界面下的程序调试工具 • 常见用法:gdb [<programfile> [<pid>]] • <programfile>:可执行程序的文件名 • <pid>:正在执行的程序的进程号 • 例如 • gdb ./hello • gdb bash 6174 • 要求: • 使用gcc/g++编译程序时,应该添加-g参数,才能实现源代码级的调试
gdb的命令(1) • 基本命令: file[<file>]打开文件<file>进行调试 run [<args>]用<args>参数来运行当前的程序 attach<pid>调试进程号为<pid>的进程 kill杀死当前调试的进程 quit退出gdb help [<topic>]显示帮助 • 单步与继续: c[ontinue]继续执行 s[tep]运行一行源代码,跟踪进入函数内部 n[ext]运行一行源代码,不进入函数内部 finish运行到函数结束并显示返回值
gdb的命令(2) • 断点 b[reak] [<where>] 设置断点, <where>可以是地址、 函数名、行号等。还可以是<文件名>:<行号>的格式 [r]watch <expr>设置观察点。每当<expr>被写(或 被读)的时候,显示该变量 catch <event>当<event>事件发生的时候程序暂 停,可用于捕获一系列的事件,包 括C++的异常 info break[points]显示出所有断点的列表 clear [<where>]清除<where>处的断点 d[elete] [<nums>]删除第<nums>个断点
gdb的命令(3) • 用于获取信息的命令: list [<where>]打印<where>处的源代码 search <regexp>在源代码中查找<regexp>表达式 backtrace [<n>]打印<n>级回溯 info [<what>]显示有关<what>的信息(如局部 变量,函数参数等) p[rint] [<expr>]显示表达式<expr>的值 • 数据修改与路径控制命令: set <name> <expr>设置变量或者参数 return [<expr>]从当前函数返回<expr>的值 jump <where>跳到<where>处执行
indent • 源代码格式美化工具 • 其功能是在源代码中插入与删除空格 • GNU风格:indent -gnu foo.c • KR风格:indent -kr foo.c • Linux内核源代码所用的风格是kr风格,且行缩进为8个空格 • indent -kr –i8 xxx.c
CVS服务器配置 • CVS=Concurrent Version System,是一种源代码版本管理系统,有助于实现团队协作 • CVS服务器的配置 • 在/etc/xinet.d/中添加cvspserver配置文件 • useradd cvs; chmod 770 /home/cvs -R • 在/etc/profile中添加export CVSROOT=/home/cvs • cvs -d /home/cvs init • 进入需要使用CVS的工程目录 • cvs import ProjName v_tag r_tag
CVS客户端的使用 • 在/etc/profile里添加export CVSROOT=:pserver:cvs@202.117.21.150:/home/cvs • cvs login:登陆 • cvs logout:退出 • cvs checkout ProjName: 下载某项工程到本地 • cvs update: 检查文件更新状况 • cvs commit: 提交文件 • cvs log: 检查文件的修改日志 • cvs add: 添加一个文件 • cvs remove: 删除一个文件
概述 • Shell程序比Windows批处理功能更强 • Shell的种类:Bourne Shell(bsh)、Bourne Again Shell(bash)、C Shell(csh)等等 • 文件第一行#!/bin/sh指明shell解释器 • 其它各行从#开始到行末的字符均为注释 • chmod +x filename使文件可执行 • shell的两种执行方式 • ./filename • /bin/sh filename
bash变量赋值 • 变量的赋值: str=“Hello, world!” • 注意等号两边不可有空格 • 接受用户输入: read str1 str2 • 特殊变量 • $0 这个程序的执行名字 • $n 这个程序的第n个参数值,n=1..9 • $* 这个程序的所有参数 • $# 这个程序的参数个数 • $$ 这个程序的PID • $! 执行上一个背景指令的PID • $? 执行上一个指令的返回值
bash表达式与变量的使用 • 变量的引用: echo $str • 变量名产生歧义时应该加{} • num=2 • echo “This is ${num}nd” • 计算表达式 • 例: expr 2 + 3 • 程序执行结果的引用: 使用一对`符号 • 例: echo "The cureent directory is "`pwd` • 例: number=`expr$number+1`
bash变量和通配符的展开 • 未加任何引号的变量和通配符会被展开 • “”可以禁止通配符的展开 • ‘’可以禁止任何展开 • \ 可用作转义字符,在expr中使用*、(、)时,必须使用\防止产生歧义 • echo *.txt 将列出当前目录所有txt文件 • echo “*.txt” *号将无法展开 • echo “this is $abc”变量abc将被展开 • echo ‘this is $abc’变量abc将无法展开 • expr 2\*\(1+3\)
bash逻辑表达式(1) int1 -eq int2 如果int1 = int2则为真 int1 -ge int2 如果int1 >= int2则为真 int1 -gt int2 如果int1 > int2则为真 int1 -le int2 如果int1 <= int2则为真 int1 -lt int2 如果int1 < int2则为真 int1 -ne int2 如果int1 != int2则为真 str1 = str2 如果str1和str2相同则为真 str1 != str2 如果str1和str2不相同则为真 str 如果str不为空则为真 -n str 如果str的长度大于零则为真 -z str 如果str的长度等于零则为真
bash逻辑表达式(2) • -d file 如果file为目录则为真 • -f file 如果file为文件则为真 • -r file 如果file为只读则为真 • -s file 如果file长度大于零则为真 • -w file 如果file可写则为真 • -x file 如果file可执行则为真 • !expr 对expr的逻辑值取反 • expr1 -a expr2 expr1和expr2相与 • expr1 -o expr2 expr1和expr2相或
Bash的If语句 if [.…]; then .... elif [.…]; then .... else .... fi 注意if和fi应成对出现
Bash的&&和|| • 以下两个语句是等价的,请注意&& • [ -f "/etc/shadow" ] && echo "This com\ puter uses shadow passwors" • if [ -f "/etc/shadow" ]; then echo "This computer uses shadow passwors" fi • 与&&相反,||在逻辑表达式为假时执行后面的语句
Bash的Case语句 case string1 in str 1) commands;; str 2) commands;; *) commands;; esac
Bash的循环语句 • For循环 for var in list; do …… done • While循环 while [……]; do …… done
Bash的函数 • 函数必须先定义后使用 • 定义函数的方法 • function foo(){……} • ()和function二者可以省略其一 • 利用$1, $2……可以取得函数的参数 • 利用local可以定义局部变量 • return只能返回0~255之间的整数 • 用$?可以取得return返回的值 • 一般通过全局变量返回函数结果
Bash函数实例 #!/bin/bash function add { local temp; temp=`expr $1 + $2` sum=`expr $temp + $3` return $sum } add 1 2 3 echo $? echo $sum
Shell脚本的自动执行(1) • 开机时自动执行 • 在/etc/rc.local中调用脚本 • 或把shell脚本直接写到/etc/rc.local中 • 用户登陆时自动执行 • /etc/profile • ~/.bash_profile • ~/.bashrc • /etc/bashrc
Shell脚本的自动执行(2) • 定时执行:atd系统服务 • at –f file HH:MM MMDDYY • atq: 显示定时任务队列 • atrm: 删除某项定时任务 • 执行的结果用email发回 • 周期性执行:crond系统服务 • crontab –e:编辑周期执行列表格式:分 时 日 月 星期 命令 • crontab –l:显示周期执行列表 • crontab –r:删除周期执行列表 • 执行的结果用email发回
正则表达式(1) • 正则表达式是用于实现字符匹配的表达式 • 基本字符 • / 转义字符,表示其后的是特殊字符 • . 匹配一个任意字符 • [] 匹配方括号内列出的任何一个字符 • [^]不匹配方括号内出现的任何一个字符 • 多字符匹配 • ?匹配0或者多个字符 • * 匹配其前面的字符0次或多次 • + 匹配其前面的字符至少一次
正则表达式(2) • 多字符匹配 • {n} 匹配其前面的字符n次 • {n,}匹配其前面的字符n次以上 • {n,N}匹配其前面的字符n~N次 • 位置匹配 • ^匹配行首 • $ 匹配行尾
正则表达式举例 • 列出当前目录下的所有子目录 • ls -al|grep "^d“ • 列出以数字作为文件名的所有文件 • ls|grep "^[0-9]*$“ • 列出文件file中包含的所有URL行 • cat file|egrep "^[a-zA-z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*([(/~?)\.-]\w*)*$" • 列出文件file中包含的所有Email地址行 • cat file|egrep "^\w(-?.?\w*)*@(\w+(-\w+)*)(\.(\w+(-\w+)*))*"
sed概述 • Sed=Stream Editor, 非交互式的流编辑器 • 用法: sed [-n] [-e 'script'] [-f script_file] file • -n:不显示输出结果 • -e:在命令行中使用脚本 • -f: 指定脚本文件名 • file:输入文件名 • Sed的脚本的基本格式如下: • [address1 [,address2] ] command [argument] • address: 行号或者行条件 • command: 是要执行的命令 • argument: 是命令的参数
sed的简单应用 • 字符串替换:将文件file中的所有ok替换成OK • sed -e 's/ok/OK/' file • 字符替换:将?结尾的行中的字母H和W换成小写 • sed -e '/?$/y/HW/hw/' file • 行前插入:在含有you的行前插入aaa • sed -e '/you/iaaa' file • 行后插入:在含有you的行后插入bbb • sed -e '/you/abbb' file • 行删除:以?结尾的行 • sed -e '/?$/d' file
awk概述 • Awk名称出自三个创建者姓氏的首字母 • 用于匹配特定的模式并执行指定的动作 • 每个awk语句总是由两部分组成 • 模式: 要匹配的字符或字符串 • 动作: 匹配成功时执行的操作 • 命令格式: awk ‘pettern { operation }’ • 当pettern为空时,operation总是被执行 • pettern可以使用正则表达式或者逻辑表达式表示 • 正则表达式应该使用//括起来 • 默认的operation为print $0,即原样输出字符串
awk的简单应用 • 显示出进程号小于100的进程的信息 • ps aux| awk '$2<100 {print $0}' • 显示出进程号大于100且用户为root的进程号和进程名称 • ps aux| awk '$1=="root" && $2>100 {print $2, $11}' • 显示出以r打头的用户id和用户名 • cat /etc/passwd| awk --field-separator=: '/^r/ {print $3, $1}' • 杀死所有名为abc的进程 • ps aux| awk '$11=="abc" {system("kill "$2)}'
练习题 • 编写、编译、运行一个简单的Java程序 • 编写一个C程序,要求程序至少具有两个C语言源文件,编写其Makefile,要求能够实现编译、安装与反安装。 • 练习CVS的基本操作 • 编写一个shell脚本,要求能够输出1~100之间的偶数 • 用awk读取/etc/passwd文件,输出其中的用户名和uid