Linux 程序设计基础

49
安安安安安 安安 西 2004 安 8 安 25 安 Linux 程程程程程程

description

Linux 程序设计基础. 西安交通大学 李思 2004 年 8 月 25 日. 主要内容. Java 程序开发环境 C/C++ 程序设计基础 使用 gcc 编译程序 LinuxC 编程与 WindowsC 编程的主要区别 使用 gdb 调试程序 Make 和 Makefile 其它工具: Indent 和 CVS Shell 编程快速入门 Bash 脚本 正则表达式, Sed 和 awk. 1.Java 程序开发环境. JDK 的安装. - PowerPoint PPT Presentation

Transcript of Linux 程序设计基础

Page 1: Linux 程序设计基础

西安交通大学 李思2004 年 8 月 25 日

Linux 程序设计基础

Page 2: Linux 程序设计基础

主要内容 Java 程序开发环境 C/C++ 程序设计基础

使用 gcc 编译程序 LinuxC 编程与 WindowsC 编程的主要区别 使用 gdb 调试程序 Make 和 Makefile 其它工具: Indent 和 CVS

Shell 编程快速入门 Bash 脚本 正则表达式, Sed 和 awk

Page 3: Linux 程序设计基础

1. Java 程序开发环境

Page 4: Linux 程序设计基础

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

注意:上面命令中不能随意添加空格 退出,重新登陆

Page 5: Linux 程序设计基础

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

Page 6: Linux 程序设计基础

其它开发工具 Linux 下常用的 Java 集成化开发环境有

JBuilder( 最新版为 X) Eclipse( 最新版为 3.0)

Eclipse 安装提示 有 motif 和 gtk 两个版本,建议选 gtk 版 安装 Eclipse 之前必须先安装 JDK 或者 JRE 用 unzip 命令解开压缩包 运行方法:eclipse -vm /usr/local/java/bin/java -vmargs -Xmx256M

Page 7: Linux 程序设计基础

2. C/C++ 程序设计基础

Page 8: Linux 程序设计基础

开发工具与开发环境 基本工具

vi, emacs, gcc, g++, gdb 图形界面调试工具 DDD 集成化开发环境

Kylix 、 Kdevelop 、 Eclipse+CDT 工程管理

版本控制: CVS 条件编译: make

Page 9: Linux 程序设计基础

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

Page 10: Linux 程序设计基础

头文件 系统默认的头文件路径为:

/usr/include 当头文件既不在源代码目录下,也不在默认目录下时,有两种办法指定其目录

在源文件中指定,例如:#include </usr/local/mysql/include> 编译时通过 -I 参数指定,例如:gcc –o foo foo.c –I /usr/local/mysql/include

一般在编写内核模块驱动程序时需要指定头文件路径

Page 11: Linux 程序设计基础

静态库文件的连接 静态库文件位于 /usr/lib 目录下,文件名为 libname.a 当使用到库函数时,应该把库函数连接到程序中去

例如: gcc -o foo.c -lm 注意: -l 的参数不是库文件名,而是库名

如果库不在 /usr/lib 下,应该采用 -L 参数指定其路径 例如 : gcc -o foo foo.c -L /root –lmylib

常用的静态库包括:数学库 m ,线程库 pthread ,动态加载库 dl等

Page 12: Linux 程序设计基础

共享库 (1) 共享库的生成

使用 -fPIC 参数生成位置无关代码 使用 -shared 参数生成共享目标库 例如 : gcc -fPIC -shared -o libfoo.so foo.c

共享库的调用 使用 dlopen函数打开共享库文件 使用 dlsym取得共享函数的指针 使用共享函数指针调用共享函数 使用 dlclose关闭共享库文件 编译方法: gcc -o foo foo.c -ldl

Page 13: Linux 程序设计基础

共享库 (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

Page 14: Linux 程序设计基础

Linux IPC概述 进程间通信 IPC是 Linux 编程与 Windows 编程最大的区别之一 Linux 下的进程间通信分为以下几类:

信号:用于进程间的事件通知,如定时器等 管道:父子进程之间单向的通信机制 信号量:用于实现进程间的同步 消息队列:用于实现异步共享通信 共享内存:用于进程间共享数据 UnixSocket :与 BSD Socket类似,但效率高于后者

Page 15: Linux 程序设计基础

Make 与 Makefile 当一个程序包含多个 C 语言源代码文件时,手工编译程序将会十分麻烦 make实际上是工程 ( 项目 ) 管理程序,它可以根据makefile 中定义的规则自动编译、安装程序 makefile可以自己编写,但更多时候是由开发工具自动生成 (autoscan, aclocal, autoconf, automake) Make 命令的格式

make [-f <makefilename>] [<target>] 如果不指定 makefilename ,默认为当前目录下的makefile 或者 Makefile Target是Makefile 中定义的目标,默认为第一个目标

Page 16: Linux 程序设计基础

Makefile 的写法 Makefile 内部可分为两部分 变量定义:

<variable>=<string value> 所有变量的默认值都源自于 Shell变量

规则定义 : < 目标 >: <依赖 > < 命令 > < 目标 >是指本条规则要生成的文件或达到的效果 <依赖 >是指执行本条规则所需要的文件或者条件,它可以是文件,也可以是其它目标 < 命令 >是指本条规则的动作, Makefile 中的第一个目标是默认的目标

Page 17: Linux 程序设计基础

Makefile实例# Example MakefileCC=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

Page 18: Linux 程序设计基础

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

Page 19: Linux 程序设计基础

GDB GDB=GNU DeBugger 它是一个文字界面下的程序调试工具 常见用法: gdb [<programfile> [<pid>]]

<programfile> :可执行程序的文件名 <pid> :正在执行的程序的进程号

例如 gdb ./hello gdb bash 6174

要求: 使用 gcc/g++ 编译程序时,应该添加 -g 参数,才能实现源代码级的调试

Page 20: Linux 程序设计基础

gdb 的命令 (1) 基本命令 :

file [<file>] 打开文件 <file> 进行调试run [<args>]用 <args> 参数来运行当前的程序attach <pid>调试进程号为 <pid> 的进程kill 杀死当前调试的进程quit 退出 gdbhelp [<topic>] 显示帮助

单步与继续 :c[ontinue] 继续执行s[tep]运行一行源代码,跟踪进入函数内部n[ext]运行一行源代码,不进入函数内部finish运行到函数结束并显示返回值

Page 21: Linux 程序设计基础

gdb 的命令 (2) 断点

b[reak] [<where>] 设置断点, <where>可以是地址、函数名、行号等。还可以是 <文件 名 >:< 行号 >的格式[r]watch <expr> 设置观察点。每当 <expr>被写( 或 被读 ) 的时候,显示该变量catch <event> 当 <event>事件发生的时候程序暂 停,可用于捕获一系列的事件,包 括 C++ 的异常info break[points] 显示出所有断点的列表clear [<where>] 清除 <where>处的断点d[elete] [<nums>] 删除第 <nums> 个断点

Page 22: Linux 程序设计基础

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>处执行

Page 23: Linux 程序设计基础

indent 源代码格式美化工具 其功能是在源代码中插入与删除空格 GNU风格: indent -gnu foo.c KR风格: indent -kr foo.c Linux 内核源代码所用的风格是 kr风格,且行缩进为 8 个空格

indent -kr –i8 xxx.c

Page 24: Linux 程序设计基础

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

Page 25: Linux 程序设计基础

CVS客户端的使用 在 /etc/profile里添加export CVSROOT=:pserver:[email protected]:/home/cvs cvs login: 登陆 cvs logout: 退出 cvs checkout ProjName: 下载某项工程到本地 cvs update: 检查文件更新状况 cvs commit: 提交文件 cvs log: 检查文件的修改日志 cvs add: 添加一个文件 cvs remove: 删除一个文件

Page 26: Linux 程序设计基础

3. Shell 编程快速入门

Page 27: Linux 程序设计基础

概述 Shell 程序比Windows批处理功能更强 Shell 的种类 :Bourne Shell(bsh) 、 Bourne Again Shell(bash) 、 C Shell(csh)等等 文件第一行 #!/bin/sh 指明 shell 解释器 其它各行从 # 开始到行末的字符均为注释 chmod +x filename 使文件可执行 shell 的两种执行方式

./filename /bin/sh filename

Page 28: Linux 程序设计基础

bash变量赋值 变量的赋值 : str=“Hello, world!” 注意等号两边不可有空格 接受用户输入 : read str1 str2 特殊变量

$0 这个程序的执行名字 $n 这个程序的第 n 个参数值, n=1..9 $* 这个程序的所有参数 $# 这个程序的参数个数 $$ 这个程序的 PID $! 执行上一个背景指令的 PID $? 执行上一个指令的返回值

Page 29: Linux 程序设计基础

bash 表达式与变量的使用 变量的引用 : echo $str 变量名产生歧义时应该加 {}

num=2 echo “This is ${num}nd”

计算表达式 例 : expr 2 + 3

程序执行结果的引用: 使用一对 `符号 例 : echo "The cureent directory is "`pwd` 例 : number=`expr $number + 1`

Page 30: Linux 程序设计基础

bash变量和通配符的展开 未加任何引号的变量和通配符会被展开 “ ”可以禁止通配符的展开 ‘ ’可以禁止任何展开 \ 可用作转义字符,在 expr 中使用 *、 ( 、 ) 时,必须使用 \ 防止产生歧义 echo *.txt 将列出当前目录所有 txt 文件 echo “*.txt” * 号将无法展开 echo “this is $abc” 变量 abc将被展开 echo ‘this is $abc’ 变量 abc将无法展开 expr 2\*\(1+3\)

Page 31: Linux 程序设计基础

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 的长度等于零则为真

Page 32: Linux 程序设计基础

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相或

Page 33: Linux 程序设计基础

Bash 的 If 语句if [.…]; then .... elif [.…]; then .... else .... fi 注意 if 和 fi应成对出现

Page 34: Linux 程序设计基础

Bash 的 &&和 || 以下两个语句是等价的,请注意 && [ -f "/etc/shadow" ] && echo "This com\ puter uses shadow passwors" if [ -f "/etc/shadow" ]; then

echo "This computer uses shadow passwors"fi

与 &&相反, ||在逻辑表达式为假时执行后面的语句

Page 35: Linux 程序设计基础

Bash 的 Case 语句case string1 instr 1)commands;;str 2)commands;;*)commands;;esac

Page 36: Linux 程序设计基础

Bash 的循环语句 For循环

for var in list; do……done

While循环while [……]; do……done

Page 37: Linux 程序设计基础

Bash 的函数 函数必须先定义后使用 定义函数的方法

function foo(){……} () 和 function二者可以省略其一

利用 $1, $2……可以取得函数的参数 利用 local可以定义局部变量 return 只能返回 0~ 255 之间的整数 用 $? 可以取得 return返回的值 一般通过全局变量返回函数结果

Page 38: Linux 程序设计基础

Bash函数实例#!/bin/bashfunction add {local temp;temp=`expr $1 + $2`sum=`expr $temp + $3`return $sum}add 1 2 3echo $?echo $sum

Page 39: Linux 程序设计基础

Shell 脚本的自动执行 (1) 开机时自动执行

在 /etc/rc.local 中调用脚本 或把 shell 脚本直接写到 /etc/rc.local中

用户登陆时自动执行 /etc/profile ~/.bash_profile ~/.bashrc /etc/bashrc

Page 40: Linux 程序设计基础

Shell 脚本的自动执行 (2) 定时执行: atd 系统服务

at –f file HH:MM MMDDYY atq: 显示定时任务队列 atrm: 删除某项定时任务 执行的结果用 email 发回

周期性执行: crond 系统服务 crontab –e :编辑周期执行列表格式:分 时 日 月 星期 命令 crontab –l :显示周期执行列表 crontab –r :删除周期执行列表 执行的结果用 email 发回

Page 41: Linux 程序设计基础

正则表达式 (1) 正则表达式是用于实现字符匹配的表达式 基本字符

/ 转义字符,表示其后的是特殊字符 . 匹配一个任意字符 [] 匹配方括号内列出的任何一个字符 [^] 不匹配方括号内出现的任何一个字符

多字符匹配 ?匹配 0 或者多个字符 * 匹配其前面的字符 0次或多次 + 匹配其前面的字符至少一次

Page 42: Linux 程序设计基础

正则表达式 (2) 多字符匹配

{n} 匹配其前面的字符 n次 {n,}匹配其前面的字符 n次以上 {n,N}匹配其前面的字符 n~N次

位置匹配 ^ 匹配行首 $ 匹配行尾

Page 43: Linux 程序设计基础

正则表达式举例 列出当前目录下的所有子目录

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+)*))*"

Page 44: Linux 程序设计基础

sed概述 Sed=Stream Editor, 非交互式的流编辑器 用法 : sed [-n] [-e 'script'] [-f script_file] file

-n: 不显示输出结果 -e: 在命令行中使用脚本 -f: 指定脚本文件名 file: 输入文件名

Sed 的脚本的基本格式如下: [address1 [,address2] ] command [argument] address: 行号或者行条件 command: 是要执行的命令 argument: 是命令的参数

Page 45: Linux 程序设计基础

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

Page 46: Linux 程序设计基础

awk概述 Awk 名称出自三个创建者姓氏的首字母 用于匹配特定的模式并执行指定的动作 每个 awk 语句总是由两部分组成

模式 : 要匹配的字符或字符串 动作 : 匹配成功时执行的操作

命令格式 : awk ‘pettern { operation }’ 当 pettern 为空时, operation总是被执行 pettern可以使用正则表达式或者逻辑表达式表示 正则表达式应该使用 //括起来 默认的 operation 为 print $0 ,即原样输出字符串

Page 47: Linux 程序设计基础

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)}'

Page 48: Linux 程序设计基础

练习题1. 编写、编译、运行一个简单的 Java 程序2. 编写一个 C 程序,要求程序至少具有两个 C 语言源文件,编写其 Makefile ,要求能够实现编译、安装与反安装。3. 练习 CVS 的基本操作4. 编写一个 shell 脚本,要求能够输出 1~100 之间的偶数5. 用 awk读取 /etc/passwd 文件,输出其中的用户名和 uid

Page 49: Linux 程序设计基础

Thank You!