Linux

Linux 使用手册

            (命令部分)

新型机项目组

                       

                              2001.12.26

目       录

简明LINUX 命令大全 4

1 Linux基本命令 4

1.1cat 4

1.2cd 4

1.3 Chmod 5

1.4chown 5

1.5 cp 6

1.6 cut 6

1.7find 7

1.8less 8

1.9locate 9

1.10ls 9

1.11more 10

1.12mv 11

1.14rm 11

1.15rmdir 11

1.16split 11

1.17touch 12

1.18at 13

1.19cal 14

1.20crontab 16

1.21date 17

1.22sleep 18

1.23 time 18

1.24uptime 21

1.25chfn 21

1.26chsh 21

1.27 finger 22

1.28last 22

1.29login 23

1.30passwd 23

1.31 who 23

1.32/etc/aliases 24

1.33mail 24

1.34mesg 25

1.35/etc/aliases 25

1.36 talk 26

1.37 wall 26

1.38write 26

1.39kill 27

1.40nice 27

1.41ps 28

1.42pstree 29

1.43renice 30

1.44top 30

1.45skill 31

1.46expr 32

1.47tr 32

1.48clear 33

1.49reset, tset 33

1.50compress 34

1.51 lpd 35

1.52lpq 35

1.53 lpr 36

1.54lprm 36

1.55 fdformat 36

1.56 mformat 37

1.57 mkdosfs 38

2GNU make 指南 42

2.0、介绍 42

2.1、多文件项目 42

2.2GNU Make 工具 46

2.3 总结 55

3GUN gcc编程 56

4linux C 编程 59

4.1、前言 59

4.2GCC 选项 60

4.3、优    61

5gdb的使用 …………………………………………………………………61

     5.1 gdb的命令行选项和参数…………………………………………62

     5.2 gdb的内部命令 …………………………………………………62

简明LINUX 命令大全

1、 Linux基本命令

1.1cat

使用权限:所有使用者 

使用方式:cat [-AbeEnstTuv] [--help] [--version] fileName 

说明:把档案串连接后传到基本输出(屏幕或> fileName 到另一个档案) 

参数: 

l -n 或 --number 由 开始对所有输出的行数编号 

l -b 或 --number-nonblank 和 -n 相似,只不过对于空白行不编号 

l -s 或 --squeeze-blank 当遇到有连续两行以上的空白行,就代换为一行的空白行 

l -v 或 --show-nonprinting 

范例: 

l cat -n textfile1 > textfile2 把 textfile1 的档案内容加上行号后输入 textfile2 这个档案里 

l cat -b textfile1 textfile2 >> textfile3 把 textfile1 和 textfile2 的档案内容加上行号(空白行不加)之后将内容附加到 textfile3 

1.2cd

使用权限 : 所有使用者 

使用方式 : cd [dirName] 

说明 : 变换工作目录至 dirName。 其中 dirName 表示法可为绝对路径或相对路径。若目录名称省略,则变换至使用者的 home directory (也就是刚 login 时所在的目录)。 另外,"~" 也表示为 home directory 的意思,"." 则是表示目前所在的目录,".." 则表示目前目录位置的上一层目录。 

范例 

l 跳到 /usr/bin/ : cd /usr/bin 

l 跳到自己的 home directory : cd ~ 

l 跳到目前目录的上上两层 cd ../.. 

1.3 、Chmod

使用权限 : 所有使用者 

使用方式 chmod [-cfvR] [--help] [--version] mode file... 

说明  Linux/Unix 的档案存取权限分为三级 档案拥有者、群组、其他。利用 

chmod 可以藉以控制档案如何被他人所存取。 

参数:

l mode : 权限设定字串,格式如下 : [ugoa...][[+-=][rwxX]...][,...],其中表示该档案的拥有者,表示与该档案的拥有者属于同一个群体(group)者,表示其他以外的人,表示这三者皆是。 

l + 表示增加权限、表示取消权限、表示唯一设定权限。 

l r 表示可读取,表示可写入,表示可执行,表示只有当该档案是个子目录或者该档案已经被设定过为可执行。 

l -c : 若该档案权限确实已经更改,才显示其更改动作 

l -f : 若该档案权限无法被更改也不要显示错误讯息 

l -v : 显示权限变更的详细资料 

l -R : 对目前目录下的所有档案与子目录进行相同的权限变更(即以递回的方式逐个变更

l --help : 显示辅助说明 

l --version : 显示版本 

范例 :

l 将档案 file1.txt 设为所有人皆可读取 chmod ugo+r file1.txt 

l 将档案 file1.txt 设为所有人皆可读取 :chmod a+r file1.txt 

l 将档案 file1.txt 与 file2.txt 设为该档案拥有者,与其所属同一个群体者可写入,但其他以外的人则不可写入 chmod ug+w,o-w file1.txt file2.txt 

l 将 ex1.py 设定为只有该档案拥有者可以执行 chmod u+x ex1.py 

l 将目前目录下的所有档案与子目录皆设为任何人可读取 

chmod -R a+r * 

l chmod也可以用数字来表示权限如 chmod 777 file 

语法为:chmod abc file 

其中a,b,c各为一个数字,分别表示UserGroup、及Other的权限。 

r=4w=2x=1 

若要rwx属性则4+2+1=7; 

若要rw-属性则4+2=6; 

若要r-x属性则4+1=7。 

l chmod a=rwx file和 chmod 777 file 效果相同 

l chmod ug=rwx,o=x file 和 chmod 771 file  效果相同 

l chmod 4755 filename可使此程式具有root的权限 

1.4chown

使用权限 : root 

使用方式 : chmod [-cfhvR] [--help] [--version] user[:group] file... 

说明 : Linux/Unix 是多人多工作业系统,所有的档案皆有拥有者。利用 chown 可以将档案的拥有者加以改变。一般来说,这个指令只有是由系统管理者(root)所使用,一般使用者没有权限可以改变别人的档案拥有者,也没有权限可以自己的档案拥有者改设为别人。只有系统管理者(root)才有这样的权限。 

参数:

l user : 新的档案拥有者的使用者 

l IDgroup : 新的档案拥有者的使用者群体

l (group)-c : 若该档案拥有者确实已经更改,才显示其更改动作

l -f : 若该档案拥有者无法被更改也不要显示错误讯息

l -h : 只对于连结(link)进行变更,而非该 link 真正指向的档案

l -v : 显示拥有者变更的详细资料

l -R : 对目前目录下的所有档案与子目录进行相同的拥有者变更(即以递回的方式逐个变更)

l --help : 显示辅助说明

l --version : 显示版本 

范例 

l 将档案file1.txt 的拥有者设为 users ,群体的使用者为jessie : chown jessie:users file1.txt 

l 将目前目录下的所有档案与子目录的拥有者皆设为 users 群体的使用者 lamport : chmod -R lamport:users * 

1.5 、cp

使用权限:所有使用者 

使用方式:cp [options] source dest 

cp [options] source... directory 

说明:将一个档案拷贝至另一档案,或将数个档案拷贝至另一目录。 

参数: 

l -a 尽可能将档案状态、权限等资料都照原状予以复制。 

l -r 若 source 中含有目录名,则将目录下之档案亦皆依序拷贝至目的地。 

l -f 若目的地已经有相同档名的档案存在,则在复制前先予以删除再行复制。 

范例: 

l 将档案 aaa 复制(已存在),并命名为 bbb : cp aaa bbb 

l 将所有的C语言程式拷贝至 Finished 子目录中 cp *.c Finished 

1.6 cut

使用权限:所有使用者 

用法:cut -cnum1-num2 filename 

说明:显示每行从开头算起 num1 到 num2 的文字。 

范例: 

l shell>> cat example 

test2 

this is test1 

l shell>> cut -c0-6 example ## print 开头算起前 个字元 

test2 

this i 

1.7find

用法 : find 

使用说明 将档案系统内符合 expression 的档案列出来。你可以指要档案的名称、类别、时间、大小、权限等不同资讯的组合,只有完全相符的才会被列出来。 

find 根据下列规则判断 path 和 expression,在命令列上第一个 - ( ) , ! 之前的部份为 path,之后的是 expression。如果 path 是空字串则使用目前路径,如果 expression 是空字串则使用 -print 为预设 expressionexpression 中可使用的选项有二三十个之多,在此只介绍最常用的部份。 

参数:

l -mount, -xdev : 只检查和指定目录在同一个档案系统下的档案,避免列出其它档案系统中的档案 

l -amin n : 在过去 分钟内被读取过 

l -anewer file : 比档案 file 更晚被读取过的档案 

l -atime n : 在过去 天过读取过的档案 

l -cmin n : 在过去 分钟内被修改过 

l -cnewer file :比档案 file 更新的档案 

l -ctime n : 在过去 天过修改过的档案 

l -empty : 空的档案-gid n or -group name : gid 是 或是 group 名称是 name 

l -ipath p, -path p : 路径名称符合 的档案,ipath 会忽略大小写 

l -name name, -iname name : 档案名称符合 name 的档案。iname 会忽略大小写 

l -size n : 档案大小 是 单位,代表 512 位元组的区块,表示字元数,表示 kilo bytes是二个位元组。

l -type c : 档案类型是 的档案。 

d: 目录 

c: 字型装置档案 

b: 区块装置档案 

p: 具名贮列 

f: 一般档案 

l: 符号连结 

s: socket 

l -pid n : process id 是 的档案 

l 你可以使用 ( ) 将运算式分隔,并使用下列运算。 

exp1 -and exp2 

! expr 

-not expr 

exp1 -or exp2 

exp1, exp2 

范例

l 将目前目录及其子目录下所有延伸档名是 的档案列出来。 

# find . -name "*.c" 

l 将目前目录其其下子目录中所有一般档案列出 

# find . -ftype f 

l 将目前目录及其子目录下所有最近 20 分钟内更新过的档案列出 

# find . -ctime -20 

1.8less

使用权限:所有使用者 

使用方式: less [Option] filename 

说明:less 的作用与 more 十分相似,都可以用来浏览文字档案的内容,不同的是 less 允许使用者往回卷动 以浏览已经看过的部份,同时因为 less 并未在一开始就读入整个档案,因此在遇上大型档案的开启时,会比一般的文书编辑器(如 vi)来的快速。 

范例: 

1.9ln

使用权限 : 所有使用者 

使用方式 : ln [options] source dist,其中 option 的格式为 

[-bdfinsvF] [-S backup-suffix] [-V {numbered,existing,simple}] 

[--help] [--version] [--] 

说明 : Linux/Unix 档案系统中,有所谓的连结(link),我们可以将其视为档案的别名,而连结又可分为两种 硬连结(hard link)与软连结(symbolic link),硬连结的意思是一个档案可以有多个名称,而软连结的方式则是产生一个特殊的档案,该档案的内容是指向另一个档案的位置。硬连结是存在同一个档案系统中,而软连结却可以跨越不同的档案系统。 ln source dist 是产生一个连结(dist)到 source,至于使用硬连结或软链结则由参数决定。不论是硬连结或软链结都不会将原本的档案复制一份,只会占用非常少量的磁碟空间。 

参数:

l -f : 链结时先将与 dist 同档名的档案删除

l -d : 允许系统管理者硬链结自己的目录

l -i : 在删除与 dist 同档名的档案时先进行询问

l -n : 在进行软连结时,将 dist 视为一般的档案

l -s : 进行软链结(symbolic link)

l -v : 在连结之前显示其档名

l -b : 将在链结时会被覆写或删除的档案进行备份

l -S SUFFIX : 将备份的档案都加上 SUFFIX 的字尾

l -V METHOD : 指定备份的方式

l --help : 显示辅助说明

l --version : 显示版本 

范例 

l 将档案 yy 产生一个 symbolic link zz : ln -s yy zz 

l 将档案 yy 产生一个 hard link zz : ln yy xx 

1.9locate

使用权限:所有使用者 

使用方式: locate [-q] [-d ] [--database=] 

locate [-r ] [--regexp=] 

locate [-qv] [-o ] [--output=] 

locate [-e ] [-f ] <[-l ] [-c] <[-U ] [-u]> 

locate [-Vh] [--version] [--help] 

说明: locate 让使用者可以很快速的搜寻档案系统内是否有指定的档案。其方法是先建立一个包括系统内所有档案名称及路径的资料库,之后当寻找时就只需查询这个资料库,而不必实际深入档案系统之中了。在一般的 distribution 之中,资料库的建立都被放在 contab 中自动执行。一般使用者在使用时只要用 # locate your_file_name 的型式就可以了。 

参数: 

l -u ,-U : 建立资料库,-u 会由根目录开始,-U 则可以指定开始的位置。 

l -e : 将排除在寻找的范围之外。 

l -l : 如果 是 1.则启动安全模式。在安全模式下,使用者不会看到权限无法看到的档案。这会始速度减慢,因为 locate 必须至实际的档案系统中取得档案的权限资料。 

l -f: 将特定的档案系统排除在外,例如我们没有到理要把 proc 档案系统中的档案放在资料库中。 

l -q : 安静模式,不会显示任何错误讯息。 

l -n : 至多显示 个输出。 

l -r : 使用正规运算式 做寻找的条件。 

l -o : 指定资料库存的名称。 

l -d : 指定资料库的路径。 

l -h: 显示辅助讯息。

l -v: 显示更多的讯息。

l -V:显示程式的版本讯息。

范例: 

l locate chdrv : 寻找所有叫 chdrv 的档案 

l locate -n 100 a.out : 寻找所有叫 a.out 的档案,但最多只显示 100 个 

l locate -u : 建立资料库 

1.10ls

使用权限 : 所有使用者 

使用方式 ls [-alrtAFR] [name...] 

说明 : 显示指定工作目录下之内容(列出目前工作目录所含之档案及子目录)。 

参数: 

l -a 显示所有档案及目录 (ls内定将档案名或目录名称开头为"."的视为隐藏档,不会列出

l -l 除档案名称外,亦将档案型态、权限、拥有者、档案大小等资讯详细列出 

l -r 将档案以相反次序显示(原定依英文字母次序

l -t 将档案依建立时间之先后次序列出 

l -A 同 -a ,但不列出 "." (目前目录及 ".." (父目录

l -F 在列出的档案名称后加一符号;例如可执行档则加 "*", 目录则加 "/" 

l -R 若目录下有档案,则以下之档案亦皆依序列出 

范例: 

l 列出目前工作目录下所有名称是 开头的档案,愈新的排愈后面 

ls -ltr s* 

l 将 /bin 目录以下所有目录及档案详细资料列出 ls -lR /bin 

l 列出目前工作目录下所有档案及目录;目录于名称后加 "/", 可执行档于名称后加 "*" : ls -AF 

1.11more

使用权限:所有使用者 

使用方式:more [-dlfpcsu] [-num] [+/pattern] [+linenum] [fileNames..] 

说明:类似 cat ,不过会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空白键(space)就往下一页显示,按 键就会往回(back)一页显示,而且还有搜寻字串的功能(与 vi 相似),使用中的说明文件,请按 。 

参数:

l -num 一次显示的行数 

l -d 提示使用者,在画面下方显示 [Press space to continue, q to quit.] ,如果使用者按错键,则会显示 [Press h for instructions.] 而不是 哔 声 

l -l 取消遇见特殊字元 ^L(送纸字元)时会暂停的功能 

l -f 计算行数时,以实际上的行数,而非自动换行过后的行数(有些单行字数太长的会被扩展为两行或两行以上) 

l -p 不以卷动的方式显示每一页,而是先清除萤幕后再显示内容 

l -c 跟 -p 相似,不同的是先显示内容再清除其他旧资料 

l -s 当遇到有连续两行以上的空白行,就代换为一行的空白行 

l -u 不显示下引号 (根据环境变数 TERM 指定的 terminal 而有所不同) 

l +/ 在每个档案显示前搜寻该字串(pattern),然后从该字串之后开始显示 

l +num 从第 num 行开始显示 

l fileNames 欲显示内容的档案,可为复数个数 

范例: 

l more -s testfile 逐页显示 testfile 之档案内容,如有连续两行以上空白行则以一行空白行显示。 

l more +20 testfile 从第 20 行开始显示 testfile 之档案内容。 

1.12mv

使用权限:所有使用者 

使用方式: mv [options] source dest 

mv [options] source... directory 

说明:将一个档案移至另一档案,或将数个档案移至另一目录。 

参数:

l -i 若目的地已有同名档案,则先询问是否覆盖旧档。 

范例:

l 将档案 aaa 更名为 bbb : mv aaa bbb 

l 将所有的C语言程式移至 Finished 子目录中 mv -i *.c 

1.14rm

使用权限:所有使用者 

使用方式:rm [options] name... 

说明:删除档案及目录。 

参数:

l -i 删除前逐一询问确认。 

l -f 即使原档案属性设为唯读,亦直接删除,无需逐一确认。 

l -r 将目录及以下之档案亦逐一删除。 

范例: 

l 删除所有C语言程式档;删除前逐一询问确认 rm -i *.c 

l 将 Finished 子目录及子目录中所有档案删除 rm -r Finished 

1.15rmdir

使用权限:于目前目录有适当权限的所有使用者 

使用方式: rmdir [-p] dirName 

说明: 删除空的目录。 

参数: 

l -p 是当子目录被删除后使它也成为空目录的话,则顺便一并删除。 

范例: 

l 将工作目录下,名为 AAA 的子目录删除 rmdir AAA 

l 在工作目录下的 BBB 目录中,删除名为 Test 的子目录。若 Test 删除后,BBB 目录成为空目录,则 BBB 亦予删除: rmdir -p BBB/Test 

1.16split

使用权限:所有使用者 

使用方式:split [OPTION] [INPUT [PREFIX]] 

说明: 将一个档案分割成数个。而从 INPUT 分割输出成固定大小的档案,其档名依序为 PREFIXaa, PREFIXab...PREFIX 预设值为 `x。若没有 INPUT 档或为 `-,则从标准输入读进资料。 

参数: 

l -b, --bytes=SIZE ,SIZE 值为每一输出档案的大小,单位为 byte。 

l -C, --line-bytes=SIZE, 每一输出档中,单行的最大 byte 数。 

l -l, --lines=NUMBER ,NUMBER值为每一输出档的列数大小。 

l -NUMBER与 -l NUMBER 相同。 

l --verbose 于每个输出档被开启前,列印出侦错资讯到标准错误输出。 

l --help 显示辅助资讯然后离开。 

l --version 列出版本资讯然后离开。 

l SIZE 可加入单位: b 代表 512, 代表 1K, 代表 1 Meg。 

范例: 

l PostgresSQL 大型资料库备份与回存:

因 Postgres 允许表格大过你系统档案的最大容量,所以要将表格 dump 到单一的档案可能会有问题,使用 split进行档案分割。 

% pg_dump dbname | split -b 1m - filename.dump. 

重新载入 

% createdb dbname 

% cat filename.dump.* | pgsql dbname 

1.17touch

使用权限:所有使用者 

使用方式:touch [-acfm] [-r reference-file] [--file=reference-file] [-t MMDDhhmm[[CC]YY][.ss]] [-d time] [--date=time] [--time={atime,access,use,mtime,modify}][--no-create] [--help] [--version] file1 [file2 ...] 

说明:touch 指令改变档案的时间记录。ls -l 可以显示档案的时间记录。

参数:

l a 改变档案的读取时间记录。 

l m 改变档案的修改时间记录。 

l c 假如目的档案不存在,不会建立新的档案。与 --no-create 的效果一样。 

l f 不使用,是为了与其他 unix 系统的相容性而保留。 

l r 使用参考档的时间记录,与 --file 的效果一样。 

l d 设定时间与日期,可以使用各种不同的格式。 

l t 设定档案的时间记录,格式与 date 指令相同。 

l --no-create 不会建立新档案。 

l --help 列出指令格式。 

l --version 列出版本讯息。 

范例:

l 最简单的使用方式,将档案的时候记录改为现在的时间。若档案不存在,系统会建立一个新的档案。 

touch file 

touch file1 file2 

将 file 的时间记录改为 月 日 18 点 分,公元两千年。时间的格式可以参考 date 指令,至少需输入 MMDDHHmm ,就是月日时与分。 

touch -c -t 05061803 file 

touch -c -t 050618032000 file 

将 file 的时间记录改变成与 referencefile 一样。 

touch -r referencefile file 

        将 file 的时间记录改成 月 日 18 点 分,公元两千年。时间可以使用 am, pm 或是 24 小时的格式,日期可以使用其他格式如 6 May 2000 。 

touch -d "6:03pm" file 

touch -d "05/06/2000" file 

touch -d "6:03pm 05/06/2000" file 

1.18at

使用权限 : 所有使用者 

使用方式 : at -V [-q queue] [-f file] [-mldbv] TIME 

说明 : at 可以让使用者指定在 TIME 这个特定时刻执行某个程式或指令,TIME 的格式是 HH:MM其中的 HH 为小时,MM 为分钟,甚至你也可以指定 am, pm, midnight, noon, teatime(就是下午 点锺)等口语词。 

如果想要指定超过一天内的时间,则可以用 MMDDYY 或者 MM/DD/YY 的格式,其中 MM 是分钟,DD 是第几日,YY 是指年份。另外,使用者甚至也可以使用像是 now + 时间间隔来弹性指定时间,其中的时间间隔可以是 minutes, hours, days, weeks 

另外,使用者也可指定 today 或 tomorrow 来表示今天或明天。当指定了时间并按下 enter 之后,at 会进入交谈模式并要求输入指令或程式,当你输入完后按下 ctrl+D 即可完成所有动作,至于执行的结果将会寄回你的帐号中。 

参数:

l -V : 印出版本编号 

l -q : 使用指定的伫列(Queue)来储存,at 的资料是存放在所谓的 queue 中,使用者可以同时使用多个 queue,而 queue 的编号为 a, b, c... z 以及 A, B, ... Z 共 52 个 

l -m : 即使程式/指令执行完成后没有输出结果也要寄封信给使用者 

l -f file : 读入预先写好的命令档。使用者不一定要使用交谈模式来输入,可以先将所有的指定先写入档案后再一次读入 

l -l : 列出所有的指定 (使用者也可以直接使用 atq 而不用 at -l) 

l -d : 删除指定 (使用者也可以直接使用 atrm 而不用 at -d) 

l -v : 列出所有已经完成但尚未删除的指定 

范例: 

l 三天后的下午 点锺执行 /bin/ls : at 5pm + 3 days /bin/ls 

l 三个星期后的下午 点锺执行 /bin/ls : at 5pm + 2 weeks /bin/ls 

l 明天的 17:20 执行 /bin/date : at 17:20 tomorrow /bin/date 

l 1999 年的最后一天的最后一分钟印出 the end of world ! at 23:59 12/31/1999 echo the end of world ! 

1.19cal 

使用权限:所有使用者 

使用方式:cal [-mjy] [month [year]] 

说明:显示日历。若只有一个参数,则代表年份(1-9999),显示该年的年历。年份必须全部写出:``cal 89\ 将不会是显示 1989 年的年历。使用两个参数,则表示月份及年份。若没有参数则显示这个月的月历。 

1752 年 月第 日起改用西洋新历,因这时大部份的国家都采用新历,有 10 天被去除,所以该月份的月历有些不同。在此之前为西洋旧历。 

参数:

l -m : 以星期一为每周的第一天方式显示。 

l -j : 以凯撒历显示,即以一月一日起的天数显示。 

l -y : 显示今年年历。 

范例: 

l cal : 显示本月的月历。

[root@mylinux /root]# date 

Tue Aug 15 08:00:18 CST 2000 

[root@mylinux /root]# cal 

August 2000 

Su Mo Tu We Th Fr Sa 

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 

[root@mylinux /root]# 

l cal 2001 : 显示公元 2001 年年历。 

[root@mylinux /root]# cal 2001 

2001 

January February March 

Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 

1 2 3 4 5 6 1 2 3 1 2 3 

7 8 9 10 11 12 13 4 5 6 7 8 9 10 4 5 6 7 8 9 10 

14 15 16 17 18 19 20 11 12 13 14 15 16 17 11 12 13 14 15 16 17 

21 22 23 24 25 26 27 18 19 20 21 22 23 24 18 19 20 21 22 23 24 

28 29 30 31 25 26 27 28 25 26 27 28 29 30 31 

April May June 

Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 

1 2 3 4 5 6 7 1 2 3 4 5 1 2 

8 9 10 11 12 13 14 6 7 8 9 10 11 12 3 4 5 6 7 8 9 

15 16 17 18 19 20 21 13 14 15 16 17 18 19 10 11 12 13 14 15 16 

22 23 24 25 26 27 28 20 21 22 23 24 25 26 17 18 19 20 21 22 23 

29 30 27 28 29 30 31 24 25 26 27 28 29 30 

July August September 

Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 

1 2 3 4 5 6 7 1 2 3 4 1 

8 9 10 11 12 13 14 5 6 7 8 9 10 11 2 3 4 5 6 7 8 

15 16 17 18 19 20 21 12 13 14 15 16 17 18 9 10 11 12 13 14 15 

22 23 24 25 26 27 28 19 20 21 22 23 24 25 16 17 18 19 20 21 22 

29 30 31 26 27 28 29 30 31 23 24 25 26 27 28 29 

30 

October November December 

Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 

1 2 3 4 5 6 1 2 3 1 

7 8 9 10 11 12 13 4 5 6 7 8 9 10 2 3 4 5 6 7 8 

14 15 16 17 18 19 20 11 12 13 14 15 16 17 9 10 11 12 13 14 15 

21 22 23 24 25 26 27 18 19 20 21 22 23 24 16 17 18 19 20 21 22 

28 29 30 31 25 26 27 28 29 30 23 24 25 26 27 28 29 

30 31 

[root@mylinux /root]# 

l cal 5 2001 : 显示公元 2001 年 月月历。 

[root@mylinux /root]# cal 5 2001 

May 2001 

Su Mo Tu We Th Fr Sa 

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 

[root@mylinux /root]# 

l cal -m : 以星期一为每周的第一天方式,显示本月的月历。 

[root@mylinux /root]# cal -m 

August 2000 

Mo Tu We Th Fr Sa Su 

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 

[root@mylinux /root]# 

l cal -jy : 以一月一日起的天数显示今年的年历。 

[root@mylinux /root]# cal -jy 

2000 

January February 

Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat 

1 32 33 34 35 36 

2 3 4 5 6 7 8 37 38 39 40 41 42 43 

9 10 11 12 13 14 15 44 45 46 47 48 49 50 

16 17 18 19 20 21 22 51 52 53 54 55 56 57 

23 24 25 26 27 28 29 58 59 60 

30 31 

March April 

Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat 

61 62 63 64 92 

65 66 67 68 69 70 71 93 94 95 96 97 98 99 

72 73 74 75 76 77 78 100 101 102 103 104 105 106 

79 80 81 82 83 84 85 107 108 109 110 111 112 113 

86 87 88 89 90 91 114 115 116 117 118 119 120 

121 

May June 

Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat 

122 123 124 125 126 127 153 154 155 

128 129 130 131 132 133 134 156 157 158 159 160 161 162 

135 136 137 138 139 140 141 163 164 165 166 167 168 169 

142 143 144 145 146 147 148 170 171 172 173 174 175 176 

149 150 151 152 177 178 179 180 181 182 

July August 

Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat 

183 214 215 216 217 218 

184 185 186 187 188 189 190 219 220 221 222 223 224 225 

191 192 193 194 195 196 197 226 227 228 229 230 231 232 

198 199 200 201 202 203 204 233 234 235 236 237 238 239 

205 206 207 208 209 210 211 240 241 242 243 244 

212 213 

September October 

Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat 

245 246 275 276 277 278 279 280 281 

247 248 249 250 251 252 253 282 283 284 285 286 287 288 

254 255 256 257 258 259 260 289 290 291 292 293 294 295 

261 262 263 264 265 266 267 296 297 298 299 300 301 302 

268 269 270 271 272 273 274 303 304 305 

November December 

Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat 

306 307 308 309 336 337 

310 311 312 313 314 315 316 338 339 340 341 342 343 344 

317 318 319 320 321 322 323 345 346 347 348 349 350 351 

324 325 326 327 328 329 330 352 353 354 355 356 357 358 

331 332 333 334 335 359 360 361 362 363 364 365 

366

[root@mylinux /root]# 

1.20crontab 

使用权限 : 所有使用者 

使用方式 crontab [ -u user ] filecrontab [ -u user ] { -l | -r | -e } 

说明 crontab 是用来让使用者在固定时间或固定间隔执行程式之用,换句话说,也就是类似使用者的时程表。-u user 是指设定指定 user 的时程表,这个前提是你必须要有其权限(比如说是 root)才能够指定他人的时程表。如果不使用 -u user 的话,就是表示设定自己的时程表。 

参数 

l -e : 执行文字编辑器来设定时程表,内定的文字编辑器是 VI,如果你想用别的文字编辑器,则请先设定 VISUAL 环境变数来指定使用那个文字编辑器(比如说 setenv VISUAL joe) 

l -r : 删除目前的时程表 

l -l : 列出目前的时程表 

l 时程表的格式如下 

f1 f2 f3 f4 f5 program 

其中 f1 是表示分钟,f2 表示小时,f3 表示一个月份中的第几日,f4 表示月份,f5 表示一个星期中的第几天。program 表示要执行的程式。 

当 f1 为 时表示每分钟都要执行 programf2 为 时表示每小时都要执行程式,其余类推 

当 f1 为 a-b 时表示从第 分钟到第 分钟这段时间内要执行,f2 为 a-b 时表示从第 到第 小时都要执行,其余类推 

当 f1 为 */n 时表示每 分钟个时间间隔执行一次,f2 为 */n 表示每 小时个时间间隔执行一次,其余类推 

当 f1 为 a, b, c,... 时表示第 a, b, c,... 分钟要执行,f2 为 a, b, c,... 时表示第 a, b, c...个小时要执行,其余类推 

使用者也可以将所有的设定先存放在档案 file 中,用 crontab file 的方式来设定时程表。 

范例 

l 每月每天每小时的第 分钟执行一次 /bin/ls : 0 7 * * * /bin/ls 

l 在 12 月内每天的早上 点到 12 点中,每隔 20 分钟执行一次 /usr/bin/backup : 0 6-12/3 * 12 * /usr/bin/backup 

l 周一到周五每天下午 5:00 寄一封信给 alex@domain.name : 0 17 * * 1-5 mail -s "hi" alex@domain.name < /tmp/maildata 

l 每月每天的午夜 点 20 , 2 点 20 , 4 点 20 ....执行 echo "haha" 20 0-23/2 * * * echo "haha" 

注意 

当程式在你所指定的时间执行后,系统会寄一封信给你,显示该程式执行的内容,若是你不希望收到这样的信,请在每一行空一格之后加上 > /dev/null 2>&1 即可。 

1.21date 

使用权限 : 所有使用者 

使用方式 date [-u] [-d datestr] [-s datestr] [--utc] [--universal] [--date=datestr] [--set=datestr] [--help] [--version] [+FORMAT] [MMDDhhmm[[CC]YY][.ss]] 

说明 

date 可以用来显示或设定系统的日期与时间,在显示方面,使用者可以设定欲显示的格式,格式设定为一个加号后接数个标记,其中可用的标记列表如下 

l 时间方面 

% : 印出 

%n : 下一行 

%t : 跳格 

%H : 小时(00..23) 

%I : 小时(01..12) 

%k : 小时(0..23) 

%l : 小时(1..12) 

%M : 分钟(00..59) 

%p : 显示本地 AM 或 PM 

%r : 直接显示时间 (12 小时制,格式为 hh:mm:ss [AP]M) 

%s : 从 1970 年 月 日 00:00:00 UTC 到目前为止的秒数 

%S : (00..61) 

%T : 直接显示时间 (24 小时制

%X : 相当于 %H:%M:%S 

%Z : 显示时区 

l 日期方面 

%a : 星期几 (Sun..Sat) 

%A : 星期几 (Sunday..Saturday) 

%b : 月份 (Jan..Dec) 

%B : 月份 (January..December) 

%c : 直接显示日期与时间 

%d : 日 (01..31) 

%D : 直接显示日期 (mm/dd/yy) 

%h : 同 %b 

%j : 一年中的第几天 (001..366) 

%m : 月份 (01..12) 

%U : 一年中的第几周 (00..53) (以 Sunday 为一周的第一天的情形

%w : 一周中的第几天 (0..6) 

%W : 一年中的第几周 (00..53) (以 Monday 为一周的第一天的情形

%x : 直接显示日期 (mm/dd/yy) 

%y : 年份的最后两位数字 (00.99) 

%Y : 完整年份 (0000..9999) 

若是不以加号作为开头,则表示要设定时间,而时间格式为    MMDDhhmm[[CC]YY][.ss],其中 MM 为月份,DD 为日,hh 为小时,mm 为  分钟,CC 为年份前两位数字,YY 为年份后两位数字,ss 为秒数 

参数 

l -d datestr : 显示 datestr 中所设定的时间 (非系统时间

l --help : 显示辅助讯息 

l -s datestr : 将系统时间设为 datestr 中所设定的时间 

l -u : 显示目前的格林威治时间 

l --version : 显示版本编号 

范例 

l 显示时间后跳行,再显示目前日期 date +%T%n%D 

l 显示月份与日数 date +%B %d 

l 显示日期与设定时间(12:34:56) : date --date 12:34:56 

注意 

当你不希望出现无意义的 (比如说 1999/03/07),则可以在标记中插入 符号,比如说 date +%-H:%-M:%-S 会把时分秒中无意义的 给去掉,像是原本的 08:09:04 会变为 8:9:4。另外,只有取得权限者(比如说 root)才能设定系统时间。 

当你以 root 身分更改了系统时间之后,请记得以 clock -w 来将系统时间写入 CMOS 中,这样下次重新开机时系统时间才会持续抱持最新的正确值。 

1.22sleep 

使用权限 : 所有使用者 

使用方式 : sleep [--help] [--version] number[smhd] 

说明 sleep 可以用来将目前动作延迟一段时间 

参数

l --help : 显示辅助讯息 

l --version : 显示版本编号 

l number : 时间长度,后面可接 sm或 其中 为秒,为 分钟,为小时,为日数 

范例 

l 显示目前时间后延迟 分钟,之后再次显示时间 date;sleep 1m;date 

1.23、 time 

使用权限: 所有使用者 

使用方式: time [options] COMMAND [arguments] 

说明: time 指令的用途,在于量测特定指令执行时所需消耗的时间及系统资源等资讯。例如 CPU 时间、记忆体、输入输出等等。需要特别注意的是,部分资讯在 Linux 上显示不出来。这是因为在 Linux 上部分资源的分配函式与 time 指令所预设的方式并不相同,以致于 time 指令无法取得这些资料。 

参数: 

l -o or --output=FILE ,设定结果输出档。这个选项会将 time 的输出写入 所指定的档案中。如果档案已经存在,系统将覆写其内容。 

l -a or --append ,配合 -o 使用,会将结果写到档案的末端,而不会覆盖掉原来的内容。 

l -f FORMAT or --format=FORMAT ,以 FORMAT 字串设定显示方式。当这个选项没有被设定的时候,会用系统预设的格式。不过你可以用环境变数 time 来设定这个格式,如此一来就不必每次登入系统都要设定一次。 

一般设定上,你可以用 

\t ,表示跳栏,或者是用 

\n ,表示换行。每一项资料要用 做为前导。如果要在字串中使用百分比符号,就用 。(学过 语言的人大概会觉得很熟悉) 

time 指令可以显示的资源有四大项,分别是: 

Time resources 

Memory resources 

IO resources 

Command info 

详细的内容如下: 

Time Resources ,执行指令所花费的时间,格式是:[hour]:minute:second。请注意这个数字并不代表实际的 CPU 时间。 执行指令所花费的时间,单位是秒。请注意这个数字并不代表实际的 CPU 时间。 指令执行时在核心模式(kernel mode)所花费的时间,单位是秒。 指令执行时在使用者模式(user mode)所花费的时间,单位是秒。 执行指令时 CPU 的占用比例。其实这个数字就是核心模式加上使用者模式的 CPU 时间除以总时间。 

Memory Resources ,执行时所占用的实体记忆体的最大值。单位是 KB t 执行时所占用的实体记忆体的平均值,单位是 KB 执行程序所占用的记忆体总量(stack+data+text)的平均大小,单位是 KB 执行程序的自有资料区(unshared data area)的平均大小,单位是 KB 执行程序的自有堆叠(unshared stack)的平均大小,单位是 ,KB X 执行程序间共享内容(shared text)的平均值,单位是 KB 系统记忆体页的大小,单位是 byte。对同一个系统来说这是个常数 

IO Resources ,此程序的主要记忆体页错误发生次数。所谓的主要记忆体页错误是指某一记忆体页已经置换到置换档(swap file)中,而且已经分配给其他程序。此时该页的内容必须从置换档里再读出来。此程序的次要记忆体页错误发生次数。所谓的次要记忆体页错误是指某一记忆体页虽然已经置换到置换档中,但尚未分配给其他程序。此时该页的内容并未被破坏,不必从置换档里读出来,此程序被交换到置换档的次数 ,此程序被强迫中断(像是分配到的 CPU 时间耗尽)的次数 ,此程序自愿中断(像是在等待某一个 I/O 执行完毕,像是磁碟读取等等)的次数 ,此程序所输入的档案数 ,此程序所输出的档案数 ,此程序所收到的 Socket Message 此程序所送出的 Socket Message 此程序所收到的信号 ( Signal )数量 

Command Info ,执行时的参数以及指令名称 ,指令的结束代码 ( Exit Status ) 

l -p or --portability ,个选项会自动把显示格式设定成为: real %e ,ser %U ,ys %S ,么做的目的是为了与 POSIX 规格相容。 

l -v or --verbose ,这个选项会把所有程式中用到的资源通通列出来,不但如一般英文语句,还有说明。对不想花时间去熟习格式设定或是刚刚开始接触这个指令的人相当有用。 

范例: 

l 利用下面的指令time -v ps -aux 

我们可以获得执行 ps -aux 的结果和所花费的系统资源。如下面所列的资料: USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND 

root 1 0.0 0.4 1096 472 ? S Apr19 0:04 init 

root 2 0.0 0.0 0 0 ? SW Apr19 0:00 [kflushd] 

root 3 0.0 0.0 0 0 ? SW Apr19 0:00 [kpiod] 

...... 

root 24269 0.0 1.0 2692 996 pts/3 R 12:16 0:00 ps -aux 

Command being timed: "ps -aux" 

User time (seconds): 0.05 

System time (seconds): 0.06 

Percent of CPU this job got: 68% 

Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.16 

Average shared text size (kbytes): 0 

Average unshared data size (kbytes): 0 

Average stack size (kbytes): 0 

Average total size (kbytes): 0 

Maximum resident set size (kbytes): 0 

Average resident set size (kbytes): 0 

Major (requiring I/O) page faults: 238 

Minor (reclaiming a frame) page faults: 46 

Voluntary context switches: 0 

Involuntary context switches: 0 

Swaps: 0 

File system inputs: 0 

File system outputs: 0 

Socket messages sent: 0 

Socket messages received: 0 

Signals delivered: 0 

Page size (bytes): 4096 

Exit status: 0 

1.24uptime 

使用权限: 所有使用者 

使用方式: uptime [-V] 

说明: uptime 提供使用者下面的资讯,不需其他参数: 

现在的时间 

系统开机运转到现在经过的时间 

连线的使用者数量 

最近一分钟,五分钟和十五分钟的系统负载 

参数: 

l -V 显示版本资讯。 

范例: 

l uptime ,其结果为: 10:41am up 5 days, 10 min, 1 users, load average: 0.00, 0.00, 1.99 

1.25chfn 

使用权限:所有使用者 

使用方式:shell>> chfn 

说明:提供使用者更改个人资讯,用于 finger and mail username 

范例: 

shell>> chfn 

Changing finger information for user 

Password: [del] 

Name[]:Johnney Huang ### 提供 finger 时的资料 

Office[]:NCCU 

Office Phone[]: [del]  

Home Phone[]: [del] 

1.26chsh 

使用权限:所有使用者 

使用方式:shell>> chsh 

说明:更改使用者 shell 设定 

范例: 

l shell>> chsh 

Changing fihanging shell for user1 

Password: [del] 

New shell [/bin/tcsh]: ### [是目前使用的 shell] 

[del] 

l shell>> chsh -l ### 展示 /etc/shells 档案内容 

/bin/bash 

/bin/sh 

/bin/ash 

/bin/bsh 

/bin/tcsh 

/bin/csh 

” finger [返回

1.27、 finger 

使用权限: 所有使用者 

使用方式: finger [options] user[@address] 

说明:finger 可以让使用者查询一些其他使用者的资料。

会列出来的资料有:Login Name 

User Name 

Home directory 

Shell 

Login status 

mail status 

.plan 

.project 

.forward 

其中 .plan .project 和 .forward 就是使用者在他的 Home Directory 里的 .plan , .project 和 .forward 等档案里的资料。如果没有就没有。finger 指令并不限定于在同一伺服器上查询,也可以寻找某一个远端伺服器上的使用者。只要给一个像是 E-mail address 一般的地址即可。 

参数: 

l -l ,多行显示。

l -s ,单行显示。这个选项只显示登入名称,真实姓名,终端机名称,闲置时间,登入时间,办公室号码及电话号码。如果所查询的使用者是远端伺服器的使用者,这个选项无效。 

范例:

l 下列指令可以查询本机管理员的资料: 

finger root 

其结果如下: 

Login: root Name: root 

Directory: /root Shell: /bin/bash 

Never logged in. 

No mail. 

No Plan. 

1.28last 

使用权限:所有使用者 

使用方式:shell>> last [options] 

说明:显示系统开机以来获是从每月初登入者的讯息 

参数:

l -R 省略 hostname 的栏位 

l -num 展示前 num 个 ,username 展示 username 的登入讯息 ,tty 限制登入讯息包含终端机代号 

范例: 

l shell>> last -R -2 

johnney pts/1 Mon Aug 14 20:42 still logged in 

johnney pts/0 Mon Aug 14 19:59 still logged in 

wtmp begins Tue Aug 1 09:01:10 2000 ### /var/log/wtmp 

l shell>> last -2 minery 

minery pts/0 140.119.217.115 Mon Aug 14 18:37 - 18:40 (00:03) 

minery pts/0 140.119.217.115 Mon Aug 14 17:22 - 17:24 (00:02) 

wtmp begins Tue Aug 1 09:01:10 2000 

1.29login 

这个命令都不会就不要干算了!呵呵我也不在这里多费笔墨耽误大家美好青春了^_^ 

1.30passwd 

使用权限:所有使用者 

使用方式:passwd [-k] [-l] [-u [-f]] [-d] [-S] [username] 

说明:用来更改使用者的密码 

参数: 

l -k 

l -l 

l -u 

l -f 

l -d ,关闭使用者的密码认证功能使用者在登入时将可以不用输入密码只有具备 root 权限的使用者方可使用

l -S 显示指定使用者的密码认证种类只有具备 root 权限的使用者方可使用

范例:

l [username] 指定帐号名称

1.31、 who 

使用权限 : 所有使用者都可使用 

使用方式 : who - [husfV] [user] 

说明 : 显示系统中有那些使用者正在上面,显示的资料包含了使用者 ID,使用的终端机,从那边连上来的,上线时间,呆滞时间,CPU 使用量,动作等等。 

参数 : 

l -h : 不要显示标题列 

l -u : 不要显示使用者的动作/工作 

l -s : 使用简短的格式来显示 

l -f : 不要显示使用者的上线位置 

l -V : 显示程式版本 

1.32/etc/aliases 

使用权限:系统管理者 

使用方式: 请用 newaliases 更新资料库 

说明: sendmail 会使用一个在 /etc/aliases 中的档案做使用者名称转换的动作。当 sendmail 收到一个要送给 xxx 的信时,它会依据 aliases档的内容送给另一个使用者。这个功能可以创造一个只有在信件系统内才有效的使用者。例如 mailing list 就会用到这个功能,在 mailinglist 中,我们可能会创造一个叫 redlinux@link.ece.uci.edu 的 mailinglist,但实际上并没有一个叫 redlinux 的使用者。实际 aliases 档的内容是将送给这个使用者的信都收给 mailing list 处理程式负责分送的工作。 

/etc/aliases 是一个文字模式的档案,sendmail 需要一个二进位格式的 /etc/aliases.dbnewaliases 的功能传是将 /etc/aliases 转换成一个 sendmail 所能了解的资料库。

范例: 

l # newaliases 

下面命令会做相同的事, 

# sendmail -bi 

相关命令

mail, mailq, newaliases, sendmail 

” mail [返回

1.33mail 

使用权限:所有使用者 

使用方式:mail [-iInv] [-s subject] [-c cc-addr] [-b bcc-addr] user1 [user 2 ...] 

说明: mail 不仅只是一个指令, mail 还是一个电子邮件程式,不过利用 mail 来读信的人应该很少吧!对于系统管理者来说 mail 就很有用,因为管理者可以用 mail 写成 script ,定期寄一些备忘录提醒系统的使用者。 

参数: 

l i 忽略 tty 的中断讯号。 (interrupt) 

l I 强迫设成互动模式。 (Interactive) 

l v 列印出讯息,例如送信的地点、状态等等。 (verbose) 

l n 不读入 mail.rc 设定档。 

l s 邮件标题。 

l c cc 邮件地址。 

l b bcc 邮件地址。 

范例: 

l 将信件送给一个或以上的电子邮件地址,由于没有加入其他的选项,使用者必须输入标题与信件的内容等。而 user2 没有主机位置,就会送给邮件伺服器的 user2 使用者。 

mail user1@email.address 

mail user1@email.address user2 

l 将 mail.txt 的内容寄给 user2 同时 cc 给 user1 。如果将这一行指令设成 cronjob 就可以定时将备忘录寄给系统使用者。 

mail -s 标题 -c user1 user2 < mail.txt 

1.34mesg 

使用权限 : 所有使用者 

使用方式 : mesg [y|n] 

说明 :决定是否允许其他人传讯息到自己的终端机介面 

参数:  

l y : 允许讯息传到终端机介面上。 

l n : 不允许讯息传到终端机介面上 。 

如果没有设定,则讯息传递与否则由终端机界面目前状态而定。 

范例 : 

l 改变目前讯息设定,改成不允许讯息传到终端机介面上 mesg n 

与 mesg 相关的指令有: talkwritewall。 

1.35/etc/aliases 

使用权限:系统管理者 

使用方式: newaliases 

说明: sendmail 会使用一个在 /etc/aliases 中的档案做使用者名称转换的动作。当 sendmail 收到一个要送给 xxx 的信时,它会依据 aliases档的内容送给另一个使用者。这个功能可以创造一个只有在信件系统内才有效的使用者。例如 mailing list 就会用到这个功能,在 mailinglist 中,我们可能会创造一个叫 redlinux@link.ece.uci.edu 的 mailinglist,但实际上并没有一个叫 redlinux 的使用者。实际 aliases 档的内容是将送给这个使用者的信都收给 mailing list 处理程式负责分送的工作。 

/etc/aliases 是一个文字模式的档案,sendmail 需要一个二进位格式的 /etc/aliases.dbnewaliases 的功能传是将 /etc/aliases 转换成一个 sendmail 所能了解的资料库。 

参数:没有任何参数。 

范例: 

l # newaliases 

下面命令会做相同的事, 

l # sendmail -bi 

相关命令:  

mail, mailq, newaliases, sendmail

1.36、 talk 

使用权限 : 所有使用者 

使用方式 :talk person [ttyname] 

说明 : 与其他使用者对谈 

参数 : 

l person : 预备对谈的使用者帐号,如果该使用者在其他机器上,则可输入 person@machine.name 

l ttyname : 如果使用者同时有两个以上的 tty 连线,可以自行选择合适的 tty 传讯息 

范例 : 

l 与现在机器上的使用者Rollaend对谈,此时 Rollaend 只有一个连线 talk Rollaend ,接下来就是等Rollaend回应,若Rollaend接受,则Rollaend输入 `talk jzlee`即可开始对谈,结束请按 ctrl+c 

l 与linuxfab.cx上的使用者Rollaend对谈,使用pts/2来对谈 talk Rollaend@linuxfab.cx pts/2 ,接下来就是等Rollaend回应,若Rollaend接受,则Rollaend输入 `talk jzlee@jzlee.home`即可开始对谈,结束请按 ctrl+c 

注意 : 若萤幕的字会出现不正常的字元,试着按 ctrl+l 更新萤幕画面。 

1.37、 wall 

使用权限 : 所有使用者 

使用方式 :wall [ message ] 

说明:wall 会将讯息传给每一个 mesg 设定为 yes 的上线使用者。当使用终端机介面做为标准传入时讯息结束时需加上 EOF (通常用 Ctrl+D) 

范例 : 

l 传讯息"hi" 给每一个使用者 wall hi 

1.38write 

使用权限 : 所有使用者 

使用方式 : write user [ttyname] 

说明 : 传讯息给其他使用者 

参数 : 

l user : 预备传讯息的使用者帐号 

l ttyname : 如果使用者同时有两个以上的 tty 连线,可以自行选择合适的 tty 传讯息 

范例:

l 传讯息给 Rollaend,此时 Rollaend 只有一个连线 write Rollaend ,接下来就是将讯息打上去,结束请按 ctrl+c 

l 传讯息给 RollaendRollaend 的连线有 pts/2pts/3 : write Rollaend pts/2 接下来就是将讯息打上去,结束请按 ctrl+c 

注意 : 若对方设定 mesg n,则此时讯席将无法传给对方 

1.39kill 

使用权限:所有使用者 

使用方式: kill [ -s signal | -p ] [ -a ] pid ... kill -l [ signal ] 

说明:kill 送出一个特定的信号 (signal) 给行程 id 为 pid 的行程根据该信号而做特定的动作若没有指定预设是送出终止 (TERM) 的信号 

参数: 

l -s (signal) : 其中可用的讯号有 HUP (1), KILL (9), TERM (15), 分别代表着重跑砍掉结束详细的信号可以用 kill -l 

l -p : 印出 pid , 并不送出信号 

l -l (signal) : 列出所有可用的信号名称 

范例: 

l 将 pid 为 323 的行程砍掉 (kill) : kill -9 323 

l 将 pid 为 456 的行程重跑 (restart) : kill -HUP 456 

1.40nice 

使用权限:所有使用者 

使用方式:nice [-n adjustment] [-adjustment] [--adjustment=adjustment] [--help] [--version] [command [arg...]] 

说明:以更改过的优先序来执行程式如果未指定程式则会印出目前的排程优先序内定的 adjustment 为 10, 范围为 -20 (最高优先序到 19 (最低优先序

-n adjustment, -adjustment, --adjustment=adjustment 皆为将该原有优先序的增加 adjustment 

参数:

l --help 显示求助讯息 

l --version 显示版本资讯 

范例: 

l 将 ls 的优先序加 并执行 nice -n 1 ls 

l 将 ls 的优先序加 10 并执行 : nice ls将 ls 的优先序加 10 并执行 

注意 : 优先序 (priority) 为作业系统用来决定 CPU 分配的参数,Linux 使用『回合制(round-robin)』的演算法来做 CPU 排程,优先序越高,所可能获得的 CPU时间就越多。 

1.41ps 

使用权限:所有使用者 

使用方式:ps [options] [--help] 

说明:显示瞬间行程 (process) 的动态 

参数: 

l ps 的参数非常多在此仅列出几个常用的参数并大略介绍含义 

l -A 列出所有的行程 

l -w 显示加宽可以显示较多的资讯 

l -au 显示较详细的资讯 

l -aux 显示所有包含其他使用者的行程 

l -au(x) 输出格式 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND 

USER: 行程拥有者 

PID: pid 

%CPU: 占用的 CPU 使用率 

%MEM: 占用的记忆体使用率 

VSZ: 占用的虚拟记忆体大小 

RSS: 占用的记忆体大小 

TTY: 终端的次要装置号码 (minor device number of tty) 

STAT: 该行程的状态

D: 不可中断的静止 (通悸□□缜b进行 I/O 动作

R: 正在执行中 

S: 静止状态 

T: 暂停执行 

Z: 不存在但暂时无法消除 

W: 没有足够的记忆体分页可分配 

<: 高优先序的行程 

N: 低优先序的行程 

L: 有记忆体分页分配并锁在记忆体内 (即时系统或捱A I/O) 

START: 行程开始时间 

TIME: 执行的时间 

COMMAND:所执行的指令 

范例: 

l ps 

PID TTY TIME CMD 

2791 ttyp0 00:00:00 tcsh 

3092 ttyp0 00:00:00 ps 

% ps -A 

PID TTY TIME CMD 

1 ? 00:00:03 init 

2 ? 00:00:00 kflushd 

3 ? 00:00:00 kpiod 

4 ? 00:00:00 kswapd 

5 ? 00:00:00 mdrecoveryd 

.......  

% ps -aux 

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND 

root 1 0.0 0.7 1096 472 ? S Sep10 0:03 init [3] 

root 2 0.0 0.0 0 0 ? SW Sep10 0:00 [kflushd] 

root 3 0.0 0.0 0 0 ? SW Sep10 0:00 [kpiod] 

root 4 0.0 0.0 0 0 ? SW Sep10 0:00 [kswapd] 

........ 

1.42pstree 

使用权限:所有使用者 

使用方式: pstree [-a] [-c] [-h|-Hpid] [-l] [-n] [-p] [-u] [-G|-U] [pid|user] ,pstree -V 

说明:将所有行程以树状图显示树状图将会以 pid (如果有指定或是以 init 这个基本行程为根 (root) ,如果有指定使用者 id , 则树状图会只显示该使用者所拥有的行程 

参数: 

l -a 显示该行程的完整指令及参数如果是被记忆体置换出去的行程则会加上括号 

l -c 如果有重覆的行程名则分开列出 (预设值是会在前面加上 

范例: 

l pstree 

init-+-amd 

|-apmd 

|-atd 

|-httpd---10*[httpd] 

%pstree -p 

init(1)-+-amd(447) 

|-apmd(105) 

|-atd(339) 

%pstree -c 

init-+-amd 

|-apmd 

|-atd 

|-httpd-+-httpd 

| |-httpd 

| |-httpd 

| |-httpd 

.... 

1.43renice 

使用权限:所有使用者 

使用方式:renice priority [[-p] pid ...] [[-g] pgrp ...] [[-u] user ...] 

说明:重新指定一个或多个行程(Process)的优先序(一个或多个将根据所下的参数而定

参数: 

l -p pid 重新指定行程的 id 为 pid 的行程的优先序 

l -g pgrp 重新指定行程群组(process group)的 id 为 pgrp 的行程 (一个或多个的优先序 

l -u user 重新指定行程拥有者为 user 的行程的优先序 

范例: 

l 将行程 id 为 987 及 32 的行程与行程拥有者为 daemon 及 root 的优先序号码加 1 : 

renice +1 987 -u daemon root -p 32 

注意 : 每一个行程(Process)都有一个唯一的 (unique) id 

1.44top 

使用权限:所有使用者 

使用方式:top [-] [d delay] [q] [c] [S] [s] [i] [n] [b] 

说明:即时显示 process 的动态 

参数: 

l d : 改变显示的更新速度,或是在交谈式指令列( interactive command)按 

l q : 没有任何延迟的显示速度,如果使用者是有 superuser 的权限,则 top 将会以最高的优先序执行 

l c : 切换显示模式,共有两种模式,一是只显示执行档的名称,另一种是显示完整的路径与名称S : 累积模式,会将己完成或消失的子行程 ( dead child process ) 的 CPU time 累积起来 

l s : 安全模式,将交谈式指令取消避免潜在的危机 

l i : 不显示任何闲置 (idle) 或无用 (zombie) 的行程 

l n : 更新的次数,完成后将会退出 top 

l b : 批次档模式,搭配 "n" 参数一起使用,可以用来将 top 的结果输出到档案内 

范例: 

l 显示更新十次后退出 top -n 10 

使用者将不能利用交谈式指令来对行程下命令 top -s 

将更新显示二次的结果输入到名称为 top.log 的档案里 :top -n 2 -b < top.log 

1.45skill 

使用权限:所有使用者 

使用方式: skill [signal to send] [options] 选择程序的规则 

说明: 送个讯号给正在执行的程序,预设的讯息为 TERM (中断) , 较常使用的讯息为 HUP , INT , KILL , STOP , CONT ,和 ,讯息有三种写法:分别为 -9 , -SIGKILL , -KILL , 可以使用 -l 或 -L 已列出可使用的讯息。 

一般参数: 

l -f 快速模式/尚未完成 

l -i 互动模式每个动作将要被确认 

l -v 详细输出列出所选择程序的资讯 

l -w 智能警告讯息尚未完成 

l -n 没有动作显示程序代号 

参数:

选择程序的规则可以是终端机代号,使用者名称,程序代号,命令名称。 

l -t 终端机代号 ( tty 或 pty ) 

l -u 使用者名称  

l -p 程序代号 ( pid ) 

l -c 命令名称 可使用的讯号

以下列出已知的讯号名称,讯号代号,功能。 

名称 (代号功能描述 

ALRM 14 离开 

HUP 1 离开 

INT 2 离开 

KILL 9 离开强迫关闭 

PIPE 13 离开 

POLL 离开 

PROF 离开 

TERM 15 离开 

USR1 离开 

USR2 离开 

VTALRM 离开 

STKFLT 离开只适用于i386, m68k, arm 和 ppc 硬体 

UNUSED 离开只适用于i386, m68k, arm 和 ppc 硬体 

TSTP 停止 /产生与内容相关的行为 

TTIN 停止 /产生与内容相关的行为 

TTOU 停止 /产生与内容相关的行为 

STOP 停止 /强迫关闭 

CONT 从新启动 /如果在停止状态则从新启动,否则忽略 

PWR 忽略 /在某些系统中会离开 

WINCH 忽略 

CHLD 忽略 

ABRT 6 核心 

FPE 8 核心 

ILL 4 核心 

QUIT 3 核心 

SEGV 11 核心 

TRAP 5 核心 

SYS 核心 /或许尚未实作 

EMT 核心 /或许尚未实作 

BUS 核心 /核心失败 

XCPU 核心 /核心失败 

XFSZ 核心 /核心失败 

范例: 

l 停止所有在 PTY 装置上的程序 ,skill -KILL -v pts/* 

l 停止三个使用者 user1 , user2 , user3 skill -STOP user1 user2 user3 

其他相关的命令: kill 

1.46expr 

使用权限:所有使用者 

### 字串长度 

shell>> expr length "this is a test" 

14 

### 数字商数 

shell>> expr 14 % 9 

### 从位置处抓取字串 

shell>> expr substr "this is a test" 3 5 

is is 

### 数字串 only the first character 

shell>> expr index "testforthegame" e 

### 字串真实重现 

shell>> expr quote thisisatestformela 

thisisatestformela 

1.47tr 

范例:

l ### 1.比方说要把目录下所有的大写档名换为小写档名

似乎有很多方式,"tr"是其中一种

#!/bin/sh 

dir="/tmp/testdir"; 

files=`find $dir -type f`; 

for i in $files 

do 

dir_name=`dirname $i`; 

ori_filename=`basename $i` 

new_filename=`echo $ori_filename | tr [:upper:] [:lower:]` > /dev/null; 

#echo $new_filename; 

mv $dir_name/$ori_filename $dir_name/$new_filename 

done 

l ### 2.自己试验中...lowercase to uppercase 

tr abcdef...[del] ABCDE...[del] 

tr a-z A-Z 

tr [:lower:] [:upper:] 

shell>> echo "this is a test" | tr a-z A-Z > www 

shell>> cat www 

THIS IS A TEST 

l ### 3.去掉不想要的字串 

shell>> tr -d this ### 去掉有关 t.e.s.t 

this 

man 

man 

test 

l ### 4.取代字串 

shell>> tr -s "this" "TEST" 

this 

TEST 

th 

TE 

1.48clear 

用途:清除萤幕用。 

使用方法:在 console 上输入 clear。 

1.49reset, tset 

使用方法: tset [-IQqrs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal] 

使用说明: reset 其实和 tset 是一同个命令,它的用途是设定终端机的状态。一般而言,这个命令会自动的从环境变数、命令列或是其它的组态档决定目前终端机的型态。如果指定型态是 的话,这个程式会要求使用者输入终端机的型别。 

由于这个程式会将终端机设回原始的状态,除了在 login 时使用外,当系统终端机因为程式不正常执行而进入一些奇怪的状态时,你也可以用它来重设终端机例如不小心把二进位档用 cat 指令进到终端机,常会有终端机不再回应键盘输入,或是回应一些奇怪字元的问题。此时就可以用 reset 将终端机回复至原始状态。

参数: 

l -p ,将终端机类别显示在萤幕上,但不做设定的动作。这个命令可以用来取得目前终端机的类别。 

l -e ch ,将 erase 字元设成 ch 

l -i ch ,将中断字元设成 ch 

l -k ch ,将删除一行的字元设成 ch 

l -I ,不要做设定的动作,如果没有使用选项 -Q 的话,erase、中断及删除字元的目前值依然会送到萤幕上。 

l -Q ,不要显示 erase、中断及删除字元的值到萤幕上。 

l -r ,将终端机类别印在萤幕上。 

l -s ,将设定 TERM 用的命令用字串的型式送到终端机中,通常在 .login 或 .profile 中用 

范例: 

l 让使用者输入一个终端机型别并将终端机设到该型别的预设状态。

# reset ? ,将 erase 字元设定 control-h 

# reset -e ^B ,将设定用的字串显示在萤幕上 

# reset -s 

Erase is control-B (^B). 

Kill is control-U (^U). 

Interrupt is control-C (^C). 

TERM=xterm; 

1.50compress 

使用权限:所有使用者 

使用方式:compress [-dfvcV] [-b maxbits] [file ...] 

说明:compress 是一个相当古老的 unix 档案压缩指令,压缩后的档案会加上一个 .Z 延伸档名以区别未压缩的档案,压缩后的档案可以以 uncompress 解压。若要将数个档案压成一个压缩档,必须先将档案 tar 起来再压缩。由于 gzip 可以产生更理想的压缩比例,一般人多已改用 gzip 为档案压缩工具。 

参数: 

l c 输出结果至标准输出设备(一般指荧幕) 

l f 强迫写入档案,若目的档已经存在,则会被覆盖 (force) 

l v 将程式执行的讯息印在荧幕上 (verbose) 

l b 设定共同字串数的上限,以位元计算,可以设定的值为 至 16 bits 。由于值越大,能使用的共同字串就 越多,压缩比例就越大,所以一般使用预设值 16 bits (bits) 

l d 将压缩档解压缩 

l V 列出版本讯息 

范例: 

l 将 source.dat 压缩成 source.dat.Z ,若 source.dat.Z 已经存在,内容则会被压缩档覆盖。  

compress -f source.dat 

l 将 source.dat 压缩成 source.dat.Z ,并列印出压缩比例。 -v 与 -f 可以一起使用 

compress -vf source.dat 

l 将压缩后的资料输出后再导入 target.dat.Z 可以改变压缩档名。compress -c source.dat > target.dat.Z 

-b 的值越大,压缩比例就越大,范围是 9-16 ,预设值是 16 。 

compress -b 12 source.dat 

l 将 source.dat.Z 解压成 source.dat ,若档案已经存在,使用者按 以确定覆盖档案,若使用 -df 程式则会自动覆盖档案。由于系统会自动加入 .Z 为延伸档名,所以 source.dat 会自动当作 source.dat.Z 处理。 

compress -d source.dat 

compress -d source.dat.Z 

1.51、 lpd 

使用权限: 所有使用者 

使用方式:lpd [-l] [#port] lpd 是一个常驻的印表机管理程式,它会根据 /etc/printcap 的内容来管理本地或远端的印表机。/etc/printcap 中定义的每一个印表机必须在 /var/lpd 中有一个相对应的目录,目录中以 cf 开头的档案表示一个等待送到适当装置的印表工作。这个档案通常是由 lpr 所产生。 

lpr 和 lpd 组成了一个可以离线工作的系统,当你使用 lpr 时,印表机不需要能立即可用,甚至不用存在。lpd 会自动监视印表机的状况,当印表机上线后,便立即将档案送交处理。这个得所有的应用程式不必等待印表机完成前一工作。 

参数: 

l -l: 将一些除错讯息显示在标准输出上。 

#port: 一般而言,lpd 会使用 getservbyname 取得适当的 TCP/IP port,你可以使用这个参数强迫 lpd 使用指定的 port。 

范例: 

l 这个程式通常是由 /etc/rc.d 中的程式在系统启始阶段执行。 

1.52lpq 

作用: 显示列表机贮列中未完成的工作 

使用方法 :lpq [l] [P] [user] 

说明 :lpq 会显示由 lpd 所管理的列表机贮列中未完成的项目。 

范例 

l 显示所有在 lp 列表机贮列中的工作 

# lpq -PlpRank Owner Job Files Total Size1st root 238 (standard input) 1428646 bytes 

相关函数 

lpr,lpc,lpd 

1.53、 lpr 

使用权限: 所有使用者 

使用方式:lpr [ -P printer ] ,将档案或是由标准输入送进来的资料送到印表机贮列之中,印表机管理程式 lpd 会在稍后将这个档案送给适当的程式或装置处理。lpr 可以用来将料资送给本地或是远端的主机来处理。 

参数: 

l -p Printer: 将资料送至指定的印表机 Printer,预设值为 lp。 

范例: 

l 将 www.c 和 kkk.c 送到印表机 lp。 

lpr -Plp www.c kkk.c 

1.54lprm 

作用:将一个工作由印表机贮列中移除 

使用方法: /usr/bin/lprm [P] [file...] 

说明:尚未完成的印表机工作会被放在印表机贮列之中,这个命令可用来将常未送到印表机的工作取消。由于每一个印表机都有一个独立的贮列,你可以用 -P 这个命令设定想要作用的印列机。如果没有设定的话,会使用系统预设的印表机。 

这个命令会检查使用者是否有足够的权限删除指定的档案,一般而言,只有档案的拥有者或是系统管理员才有这个权限。 

范例 :

l 将印表机 hpprinter 中的第 1123 号工作移除 

lprm -Phpprinter 1123 

l 将第 1011 号工作由预设印表机中移除 

lprm 1011 

1.55、 fdformat 

使用权限: 所有使用者 

使用方式:fdformat [-n] device 

说明 : 对指定的软碟机装置进行低阶格式化。使用这个指令对软碟格式化的时候,最好指定像是下面的装置: 

/dev/fd0d360 磁碟机 A: ,磁片为 360KB 磁碟 

/dev/fd0h1440 磁碟机 A: ,磁片为 1.4MB 磁碟 

/dev/fd1h1200 磁碟机 B: ,磁片为 1.2MB 磁碟 

如果使用像是 /dev/fd0 之类的装置,如果里面的磁碟不是标准容量,格式化可能会失败。在这种情况之下,使用者可以用 setfdprm 指令先行指定必要参数。 

参数:

l -n 关闭确认功能。这个选项会关闭格式化之后的确认步骤。 

范例: 

l fdformat -n /dev/fd0h1440 

将磁碟机 的磁片格式化成 1.4MB 的磁片。并且省略确认的步骤。 

1.56、 mformat 

使用权限: 所有使用者 

使用方式: mformat [-t cylinders] [-h heads] [-s sectors] [-l volume_label] [-F] [-I fsVer-sion] [-S sizecode] [-2 sectors_on_track_0] [-M software_sector_size] [-a] [-X] [-C] [-H hidden_sectors] [-r root_sectors] [-B boot_sector] [-0 rate_on_track_0] [-A rate_on_other_tracks] [-1] [-k] drive: 

在已经做过低阶格式化的磁片上建立 DOS 档案系统。如果在编译 mtools 的时候把 USE_2M 的参数打开,部分与 2M 格式相关的参数就会发生作用。否则这些参数(像是 S,2,1,M)不会发生作用。 

参数: 

l -t 磁柱(synlider)数 

l -h 磁头(head)数 

l -s 每一磁轨的磁区数 

l -l 标签 

l -F 将磁碟格式化为 FAT32 格式,不过这个参数还在实验中。 

l -I 设定 FAT32 中的版本号。这当然也还在实验中。 

l -S 磁区大小代码,计算方式为 sector = 2^(大小代码+7) 

l -c 磁丛(cluster)的磁区数。如果所给定的数字会导致磁丛数超过 FAT 表的限制,mformat 会自动放大磁区数。 

l -s 

l -M 软体磁区大小。这个数字就是系统回报的磁区大小。通常是和实际的大小相同。 

l -a 如果加上这个参数,mformat 会产生一组 Atari 系统的序号给这块软碟。 

l -X 将软碟格式化成 XDF 格式。使用前必须先用 xdfcopy 指令对软碟作低阶格式化的动作。 

l -C 产生一个可以安装 MS-DOS 档案系统的磁碟影像档(disk image)。当然对一个实体磁碟机下这个参数是没有意义的。 

l -H 隐藏磁区的数目。这通常适用在格式化硬碟的分割区时,因为通常一个分割区的前面还有分割表。这个参数未经测试,能不用就不用。 

l -n 磁碟序号 

l -r 根目录的大小,单位是磁区数。这个参数只对 FAT12 和 FAT16 有效。 

l -B 使用所指定的档案或是设备的开机磁区做为这片磁片或分割区的开机磁区。当然当中的硬体参数会随之更动。 

l -k 尽量保持原有的开机磁区。 

l -0 第 轨的资料传输率 

l -A 第 轨以外的资料传输率 

l -2 使用 2m 格式 

l -1 不使用 2m 格式 

范例: 

l mformat a: 

这样会用预设值把 a: (就是 /dev/fd0)里的磁碟片格式化。 

1.57、 mkdosfs 

使用权限: 所有使用者 

使用方式: mkdosfs [ -c | -l filename ] 

[ -f number_of_FATs ] 

[ -F FAT_size ] 

[ -i volume_id ] 

[ -m message_file ] 

[ -n volume_name ] 

[ -r root_dir_entry ] 

[ -s sector_per_cluster ] 

[ -v ] 

device 

[ block_count ] 

说明: 建立 DOS 档案系统。 device 指你想要建立 DOS 档案系统的装置代号。像是 /dev/hda1 等等。 block_count 则是你希望配置的区块数。如果 block_count 没有指定则系统会自动替你计算符合该装置大小的区块数。 

参数: 

l -c 建立档案系统之前先检查是否有坏轨。 

l -l 从得定的档案中读取坏轨记录。 

l -f 指定档案配置表(FAT , File Allocation Table)的数量。预设值为 。目前 Linux 的 FAT 档案系统不支援超过 个 FAT 表。通常这个不需要改。 

l -F 指定 FAT 表的大小,通常是 12 或是 16 个位元组。12 位元组通常用于磁碟片,16 位元组用于一般硬碟的分割区,也就是所谓的 FAT16 格式。这个值通常系统会自己选定适当的值。在磁碟片上用 FAT16 通常不会发生作用,反之在硬碟上用 FAT12 亦然。 

l -i ,指定 Volume ID。一般是一个 个位元组的数字,像是 2e203a47 。如果不给系统会自己产生。 

l -m ,当使用者试图用这片磁片或是分割区开机,而上面没有作业系统时,系统会给使用者一段警告讯息。这个参数就是用来变更这个讯息的。你可以先用档案编辑好,然后用这个参数指定,或是用 

l -m - ,这样系统会要求你直接输入这段文字。要特别注意的是,档案里的字串长度不要超过 418 个字,包括展开的跳栏符号(TAB)和换行符号(换行符号在 DOS 底下算两个字元!) 

l -n ,指定 Volume Name,就是磁碟标签。如同在 DOS 底下的 format 指令一样,给不给都可以。没有预设值。 

l -r ,指定根目录底下的最大档案数。这里所谓的档案数包括目录。预设值是在软碟上是 112 或是 224 ,在硬碟上是 512。没事不要改这个数字。 

l -s 每一个磁丛(cluster)的磁区数。必须是 的次方数。不过除非你知道你在作什么,这个值不要乱给。 

l -v 提供额外的讯息 

范例: 

l mkdosfs -n Tester /dev/fd0 将 槽里的磁碟片格式化为 DOS 格式,并将标签设为 Tester 

ifconfig 

无论是Linux自动安装还是我们手工安装,Linux都会向你询问有关网络的问题并配置相关的软件。这个用于配置网卡的基本命令就是ifconfig。  

  在执行ifconfig命令后,系统将在内核表中设置必要的参数,这样Linux就知道如何与网络上的网卡通信。ifconfig命令有以下两种格式: 

  ※ifconfig [interface] 

  ※ifconfig interface [aftype] option | address … 

  ifconfig的第一种格式(或使用不带任何参数的ifconfig命令)可以用来查看当前系统的网络配置情况。 

  在刚刚安装完系统之后,实际上是在没有网卡或者网络连接的情况下使用Linux,但通过ifconfig可以使用回绕方式工作,使计算机认为自己工作在网络上。 

  现在我们运行一下ifconfig命令,不带参数的ifconfig命令可以显示当前启动的网络接口,其输出结果为: 

----------------------------------------------------------- 

[root@machine1 /sbin]#ifconfig 

eth0 Link encap:Ethernet Hwaddr 52:54:AB:DD:6F:61 

inet addr:210.34.6.89 Bcast:210.34.6.127 Mask:255.255.255.128 

UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 

RX packets:46299 errors:0 dropped:0 overruns:0 frame:189 

TX packets:3057 errors:0 dropped:0 overruns:0 carrier:0 

collisions:0 txqueuelen:100 

Interrupt:5 Base address:0xece0 

lo Link encap:Local Loopback 

inet addr:127.0.0.1 Mask:255.0.0.0 

UP LOOPBACK RUNNING MTU:3924 Metric:1 

RX packets:44 errors:0 dropped:0 overruns:0 frame:0 

TX packets:44 errors:0 dropped:0 overruns:0 carrier:0 

collisions:0 txqueuelen:0 

-------------------------------------------------------------------- 

  其中以eth0为首的部分是本机的以太网卡配置参数,这里显示了网卡在下的设备名/dev/eth0和硬件的MAC地址52:54:AB:DD:6F:61MAC地址是生产厂家定的,每个网卡拥有的唯一地址。 

  不过我们可以手工改动网卡的MAC地址,只要我们在/etc/rc.d/init.d/中的network中加入: 

  ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx 

  然后重启,此时再用ifconfig命令查看一下,我们就会发现网卡的MAC地址已经变成xx:xx:xx:xx:xx:xx了。 

下一行显示本机的IP地址信息,分别是本机的IP地址,网络广播地址和子网掩码。必须确认这些信息都是正确无误的,否则Linux服务器无法与其它网络设备建立连接。我们也可以手工实现IPMac地址的捆绑,命令是 

  arp -i eth0 -s xxx.xxx.xxx.xxx(IP) xx.xx.xx.xx.xx(MAC) 

接下来显示的是设备的网络状态。MTU(最大传输单元)和Metric(度量值)字段显示的是该接口当前的M T U和度量值的值。按照惯例,度量值供某些操作系统所用,用于计算一条路由的成本。 

再下来显示接口通信的网络统计值。RXTX分别表示接收和传送的数据包。如果你的网卡已经完成配置却还是无法与其它设备通信,那么从RXTX的显示数据上可以简单地分析一下故障原因。在这种情况下,如果你看到接收和传送的包的计数(packets)增加,那有可能是系统的IP地址出现了混乱;如果你看到大量的错误(errors)和冲突(Collisions),那么这很有可能是网络的传输介质出了问题,例如网线不通或hub损坏。 

  再下面的Interrupt:5 Base address:0xece0显示的是网卡的中断调用号和端口号,这是两个非常重要的硬件配置信息。如果您的网卡是PCI的,那么Linux在引导时有可能会自动配置这些信息(也很有可能会让您手工配置)但目前绝大多数网卡都是PnP的,这就需要我们进行手工配置了。如果您的网卡还没有配置好,那么运行: 

  [root@machine1 /sbin]#ifconfig 

系统只会输出以lo为首的部分。lolook-back网络接口,从IP地址127.0.0.1就可以看出,它代表"本机"。无论系统是否接入网络,这个设备总是存在的,除非你在内核编译的时候禁止了网络支持,这是一个称为回送设备的特殊设备,它自动由Linux配置以提供网络的自身连接。IP地址127.0.0.1是一个特殊的回送地址(即默认的本机地址),您可以在自己的系统上用telnetIP地址127.0.0.1进行测试。如果有inetd进程在运行的话您会从自己的机器上获得登录提示符。Linux可以利用这个特征在进程与仿真网络之间进行通信。(您有兴趣的话还可以试试本机的实际IP地址,如这里的机器就是210.34.6.89,或者试试"localhost",或者"127.0.0.1",同样可以模拟网络通信。这可是Linux一个非常突出的优点!) 

如果你只是关心某个设备是否正常,可以在ifconfig后面加上接口名字: 

[root@machine1 /sbin]# ifconfig eth0 

eth0 Link encap:Ethernet HWaddr 52:54:AB:DD:6F:61 

inet addr:210.34.6.89 Bcast:210.34.6.127 Mask:255.255.255.128 

UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 

RX packets:50568 errors:0 dropped:0 overruns:0 frame:198 

TX packets:3200 errors:0 dropped:0 overruns:0 carrier:0 

collisions:0 txqueuelen:100 

Interrupt:5 Base address:0xece0 

表示eth0设备已经正常工作。 

有时需要为某个设备接口配置多个IP地址,办法是使用设备别名,例如,eth0设备可以有eth0eth0:0eth0:1....多个别名,每个都可以有一个独立的IP地址: 

ifconfig eth0 210.34.6.89 netmask 255.255.255.128 broadcast 210.34.6.127 

ifconfig eth0:0 210.34.6.88 netmask 255.255.255.128 broadcast 210.34.6.127 

这样,210.34.6.89210.34.6.88都会被绑定在eth0设备上,使用同样的网络设备,不同的IP地址。 

如果你要暂停某个网络接口的工作,使用down参数: 

ifconfig eth0 down 

    将取消eth0网络接口。与之对应的是有一个参数up,不过由于是缺省值,所以从来不用。 

  如果我们使用了带有参数的ifconfig命令,那就可以手动设置网卡的配置参数了。有效的ifconfig命令参数及其意义为(选项对应的特性可以打开也可以取消,只在选项名前加一个破折号(-)即可): 

Interface 网络设备名,如eth0就表示本机的第一块网卡。 

up 标志接口处于" up"状态,也就是说, IP层可以对其进行访问。这个选项用于命令行上给出一个地址之时。如果这个接口已被" down"选项临时性取消的话(与该选项对应的标记是UP RUNNING),还可以用于重新启用一个接口。 

down 标标志接口处于" down"状态,也就是说, IP层不能对其进行访问。这个选项有效地禁止了IP通信流通这个接口。注意,它并没有自动删除利用该接口的所有路由信息。如果永久性地取消了一个接口,就应该删除这些路由条目,并在可能的情况下,提供备用路由。 

netmask 标分配子网掩码,供接口所用。要么给一个前面是0x32位十六进制号码,要么采用只适用于两台主机所用的点分四段式号码。对SLIPPLIP接口来说,这个选项是必须配置的。 

address  设置指定接口设备的IP地址。 

dstaddr adderss PPP设置远程IP地址,此关键字可用pointopoint代替。 

irqaddress 设置指定接口设备使用的中断行。 

pointtopoint address 该选项用于只涉及两台主机的点到点链接。对SLIPPLIP接口来说,这个选项是必须配置的(如果已经设置了一个点到点地址,ifconfig就会显示出POINTTPOINT标记)。 

broadcast address 广播地址通常源于网络编号,通过设置主机部分的所有位得来。有的I P采用的方案有所不同:这个选项可适用于某些奇怪的环境(如果已经设置了广播地址, ifconfig就会显示出一个BROADCAST标记)。 

hw class addr     设置指定接口设备的MAC地址,关键字的后面必须跟硬件名或者与之等价的ASCII码。目前支持的硬件类有ether, ax25, ARCnet和 netrom。 

metric number 该选项可用于为接口创建的路由表分配度量值。路由信息协议( RIP)利用度量值来构建网络路由表。ifconfig所用的默认度量值是0。如果不运行RIP程序,就没必要采用这个选项。如果要运行RIP程序,就尽量不要改变这个默认的度量值。 

mtu bytes 该选项用于设置最大传输单元,也就是接口一次能处理的最大字节数。对以太网接口来说, MTU的默认设置是1500 个字节;对SLIP接口来说,则是296个字节。 

arp 标这个选项专用于以太网或包广播之类的广播网络。它启用ARP(地址解析协议)来保护网络上各台主机的物理地址。对广播网来说,默认设置是" on"(开)。 

promisc 将接口置入promiscuous(混乱)模式。广播网中,这样将导致该接口接收所有的数据包,不管其目标是不是另一台主机。该选项允许利用包过滤器和所谓的以太网窥视技术,对网络通信进行分析。通常情况下,这对揪出网络故障的元凶来说,是相当有用的。但另一方面,如果有人蓄意攻击你的网络,也可浏览到s通信数据,进而获得密码,破坏你的网络。一项重要的保证措施是杜绝任何人将他们的计算机接入你的以太网。另一个选项用于保护某些身份验证协议的安全,比如KerberosSRA登录套件(该选项对应的标记是PROMISC)。 

traIlers  开或关闭跟踪器。目前在某些Linux系统中还无法实现此功能。 

allmulti 多播地址即是向不在同一个子网上的一组主机广播数据。多播地址尚未获得内核支持(该选项对应的标记是ALLMULTI) 

txqueuelen len   设置指定接口设备的发送队列长度。 

由此可以看出有大量的参数可用于配置网卡,下面是在这台计算机上使用ifconfig命令的实例: 

------------------------------------------------------------------------------ 

ifconfig eth0 210.34.6.89 netmask 255.255.255.128 broadcast 210.34.6.127 

------------------------------------------------------------------------------ 

该命令的作用是设置网卡eth0IP地址,网络掩码和网络的本地广播地址。同样的方式可以用来配置eth1eth2等等,通常netmaskbroadcast只要设置一个就可以了。

2GNU make 指南 

2.0介绍

~~~~~~~~~~~~~~~ 

本文将首先介绍为什么要将你的C源代码分离成几个合理的独立档案,什么时候需要分,怎么才能分的好。然后将会告诉你 GNU Make 怎样使你的编译和连接步骤自动化。对于其它 Make 工具的用户来说,虽然在用其它类似工具时要做适当的调整,本文的内容仍然是非常有用的。如果对你自己的编程工具有怀疑,可以实际的试一试,但请先阅读用户手册。

2.1多文件项目 

2.1.1为什么使用它们? 

首先,多文件项目的好处在那里呢?它们看起来把事情弄的复杂无比。又要 header 文件,又要 extern 声明,而且如果需要查找一个文件,你要在更多的文件里搜索。但其实我们有很有力的理由支持我们把一个项目分解成小块。当你改动一行代码,编译器需要全部重新编译来生成一个新的可执行文件。但如果你的项目是分开在几个小文件里,当你改动其中一个文件的时候,别的源文件的目标文件(object files)已经存在,所以没有什么原因去重新编译它们。你所需要做的只是重现编译被改动过的那个文件,然后重新连接所有的目标文件罢了。在大型的项目中,这意味着从很长的(几分钟到几小时)重新编译缩短为十几,二十几秒的简单调整。只要通过基本的规划,将一个项目分解成多个小文件可使你更加容易的找到一段代码。很简单,你根据代码的作用把你的代码分解到不同的文件里。当你要看一段代码时,你可以准确的知道在那个文件中去寻找它。从很多目标文件生成一个程序包 (Library)比从一个单一的大目标文件生成要好的多。当然实际上这是否真是一个优势则是由你所用的系统来决定的。但是当使用 gcc/ld(一个 GNU C 编译/连接器把一个程序包连接到一个程序时,在连接的过程中,它会尝试不去连接没有使用到的部分。但它每次只能从程序包中把一个完整的目标文件排除在外。因此如果你参考一个程序包中某一个目标档中任何一个符号的话,那么这个目标文件整个都会被连接进来。要是一个程序包被非常充分的分解了的话,那么经连接后,得到的可执行文件会比从一个大目标文件组成的程序包连接得到的文件小得多。又因为你的程序是很模块化的,文件之间的共享部分被减到最少,那就有很多好处—— 

可以很容易的追踪到臭虫,这些模块经常是可以用在其它的项目里的,同时别人也可以更容易的理解你的一段代码是干 什么的。当然此外还有许多别的好处…… 

2.1.2 何时分解你的项目

很明显,把任何东西都分解是不合理的。象世界,你们好这样的简单程序根本就不能分,因为实在也没什么可分的。把用于测试用的小程序分解也是没什么意思的。但一般来说,当分解项目有助于布局、发展和易读性的时候,我都会采取它。在大多数的情况下,这都是适用的。(所谓世界,你们好,既 'hello world' ,只是一个介绍一种编程语言时惯用的范例程序,它会在屏幕上显示一行 'hello world' 。是最简单的程序。)

如果你需要开发一个相当大的项目,在开始前,应该考虑一下你将如何实现它,并且生成几个文件(用适当的名字)来放你的代码。当然,在你的项目开发的过程中,你可以建立新的文件,但如果你这么做的话,说明你可能改变了当初的想法,你应该想想是否需要对整体结构也进行相应的调整。

对于中型的项目,你当然也可以采用上述技巧,但你也可以就那么开始输入你的代码,当你的码多到难以管理的时候再把它们分解成不同的档案。但以我的经验来说,开始时在脑子里形成一个大概的方案,并且尽量遵从它,或在开发过程中,随着程序的需要而修改,会使开发变得更加容易。 

2.1.3 怎样分解项目 

先说明,这完全是我个人的意见,你可以(也许你真的会?)用别的方式来做。这会触动到有关编码风格的问题,而大家从来就没有停止过在这个问题上的争论。在这里我只是给出我自己喜欢的做法(同时也给出这么做的原因):

● 不要用一个 header 文件指向多个源码文件(例外:程序包 的 header 文件)。用一个 header定义一个源码文件的方式 会更有效,也更容易查寻。否则改变一个源文件的结构(并且 它的 header 文件)就必须重新编译好几个文件。      

● 如果可以的话,完全可以用超过一个的 header 文件来指向同 一个源码文件。有时将不可公开调用的函数原型,类型定义 等等,从它们的C源码文件中分离出来是非常有用的。使用一 个 header 文件装公开符号,用另一个装私人符号意味着如果你改变了这个源码文件的内部结构,你可以只是重新编译它而 不需要重新编译那些使用它的公开 header 文件的其它的源文 件。

● 不要在多个 header 文件中重复定义信息。 如果需要, 在其中一个 header 文件里 #include 另一个,但 是不要重复输入相同的 header 信息两次。原因是如果你以后改 变了这个信息,你只需要把它改变一次,不用搜索并改变另外一 个重复的信息。 

● 在每一个源码文件里, #include 那些声明了源码文件中的符 号的所有 header文件。这样一来,你在源码文件和 header 文件对某些函数做出的矛盾声明可以比较容易的被编译器发现。 

2.1.4 对于常见错误的注释

●定义符 (Identifier) 在源码文件中的矛盾:在C里,变量和函数的缺 省状态是公用的。因此,任何C源码档案都可以引用存在于其它源 码档中的通用 (global) 函数和通用变量,既使这个档案没有那个变 量或函数的声明或原型。因此你必须保证在不同的两个档案里不能 用同一个符号名称,否则会有连接错误或者在编译时会有警告。一种避免这种错误的方法是在公用的符号前加上跟其所在源文件有 关的前缀。比如:

所有在 gfx.c 里的函数都加上前缀“gfx_”。如果 你很小心的分解你的程序,使用有意义的函数名称,并且不是过分 使用通用变量,当然这根本就不是问题。  

要防止一个符号在它被定义的源文件以外被看到,可在它的定义前 加上关键字“static”。这对只在一个档案内部使用,其它档案都 都不会用到的简单函数是很有用的。

● 多次定义的符号: header 档会被逐字的替换到你源文件里 #include 的位置的。因此,如果 header 档被 #include 到一个以上的源文件 里,这个 header 档中所有的定义就会出现在每一个有关的源码文件 里。这会使它们里的符号被定义一次以上,从而出现连接错误(见 上)。

解决方法: 不要在 header 档里定义变量。你只需要在 header 档里声明它们然后在适当的C源码文件(应该 #include 那个 header 档的那个)里定义它们(一次)。对于初学者来说,定义和声明是 很容易混淆的。声明的作用是告诉编译器其所声明的符号应该存在, 并且要有所指定的类型。但是,它并不会使编译器分配贮存空间。 而定义的做用是要求编译器分配贮存空间。当做一个声明而不是做 定义的时候,在声明前放一个关键字“extern”

例如,我们有一个叫“counter”的变量,如果想让它成为公用的, 我们在一个源码程序(只在一个里面)的开始定义它:“int counter;”,再在相关的 header 档里声明它:“extern int counter;”

函数原型里隐含着 extern 的意思,所以不需顾虑这个问题。 

●重复定义,重复声明,矛盾类型:

请考虑如果在一个C源码文件中 #include 两个档 a.h 和 b.h, 而 a.h 又 #include了 b.h 档(原因是 b.h 档定义了一些 a.h 需要的类型),会发生什么事呢?这时该C源码文件 #include 了 b.h 两次。因此每一个在 b.h 中的 #define 都发生了两次,每一 个声明发生了两次,等等。理论上,因为它们是完全一样的拷贝, 所以应该不会有什么问题,但在实际应用上,这是不符合C的语法 的,可能在编译时出现错误,或至少是警告。

解决的方法是要确定每一个 header 档在任一个源码文件中只被包 含了一次。我们一般是用预处理器来达到这个目的的。当我们进入 每一个 header 档时,我们为这个header 档 #define 一个巨集 指令。只有在这个巨集指令没有被定义的前提下,我们才真正使用 该 header 档的主体。在实际应用上,我们只要简单的把下面一段 码放在每一个 header 档的开始部分:

#ifndef FILENAME_H

#define FILENAME_H

然后把下面一行码放在最后:

#endif

用 header 档的档名(大写的)代替上面的 FILENAME_H,用底线 代替档名中的点。有些人喜欢在 #endif 加上注释来提醒他们这个 #endif 指的是什么。例如:

#endif /* #ifndef FILENAME_H */

我个人没有这个习惯,因为这其实是很明显的。当然这只是各人的 风格不同,无伤大雅。

你只需要在那些有编译错误的 header 档中加入这个技巧,但在所 有的 header 档中都加入也没什么损失,到底这是个好习惯。

2.1.5 重新编译一个多文件项目

清楚的区别编译和连接是很重要的。编译器使用源码文件来产生某种 形式的目标文件(object files)。在这个过程中,外部的符号参考并 没有被解释或替换。然后我们使用连接器来连接这些目标文件和一些 标准的程序包再加你指定的程序包,最后连接生成一个可执行程序。 在这个阶段,一个目标文件中对别的文件中的符号的参考被解释,并 报告不能被解释的参考,一般是以错误信息的形式报告出来。

基本的步骤就应该是,把你的源码文件一个一个的编译成目标文件的格 式,最后把所有的目标文件加上需要的程序包连接成一个可执行文件。 具体怎么做是由你的编译器决定的。这里我只给出 gcc GNU C 编译 器)的有关命令,这些有可能对你的非 gcc 译器也适用。

gcc 是一个多目标的工具。它在需要的时候呼叫其它的元件(预处理 程序,编译器,组合程序,连接器)。具体的哪些元件被呼叫取决于 输入文件的类型和你传递给它的开关。

一般来说,如果你只给它C源码文件,它将预处理,编译,组合所有 的文件,然后把所得的目标文件连接成一个可执行文件(一般生成的 文件被命名为 a.out )。你当然可以这么做,但这会破坏很多我们 把一个项目分解成多个文件所得到的好处。

如果你给它一个 -c 开关,gcc 只把给它的文件编译成目标文件, 用源码文件的文件名命名但把其后缀由“.c”“.cc”变成“.o”。 如果你给它的是一列目标文件,gcc 会把它们连接成可执行文件, 缺省文件名是 a.out 。你可以改变缺省名,用开-o 后跟你指定 的文件名。 

因此,当你改变了一个源码文件后,你需要重新编译它: 'gcc -c filename.c' 然后重新连接你的项目: 'gcc -o exec_filename *.o'。 如果你改变了一个 header 档,你需要重新编译所有 #include 过 这个档的源码文件,你可以用 'gcc -c file1.c file2.c file3.c' 然后象上边一样连接。

当然这么做是很繁琐的,幸亏我们有些工具使这个步骤变得简单。 本文的第二部分就是介绍其中的一件工具:GNU Make 工具。

(好家伙,现在才开始见真章。您学到点儿东西没?)

2.2、GNU Make 工具

2.2.1 基本 makefile 结构 

GNU Make 的主要工作是读进一个文本文件, makefile 。这个文 件里主要是有关哪些文件(‘target’目的文件)是从哪些别的 文件(‘dependencies’依靠文件)中产生的,用什么命令来进行 这个产生过程。有了这些信息, make 会检查磁碟上的文件,如果 目的文件的时间戳(该文件生成或被改动时的时间)比至少它的一 个依靠文件旧的话, make 就执行相应的命令,以便更新目的文件。 (目的文件不一定是最后的可执行档,它可以是任何一个文件。) 

makefile 一般被叫做“makefile”“Makefile”。当然你可以 在 make 的命令行指定别的文件名。如果你不特别指定,它会寻 找“makefile”“Makefile”,因此使用这两个名字是最简单 的。

一个 makefile 主要含有一系列的规则,如下:

: ... 

(tab) 

(tab) 

.. 

.. 

.. 

例如,考虑以下的 makefile : 

=== makefile 开始 === 

myprog : foo.o bar.o 

gcc foo.o bar.o -o myprog 

foo.o : foo.c foo.h bar.h 

gcc -c foo.c -o foo.o 

bar.o : bar.c bar.h 

gcc -c bar.c -o bar.o 

=== makefile 结束 === 

这是一个非常基本的 makefile —— make 从最上面开始,把上 面第一个目的,‘myprog’,做为它的主要目标(一个它需要保 证其总是最新的最终目标)。给出的规则说明只要文件‘myprog’ 比文件‘foo.o’‘bar.o’中的任何一个旧,下一行的命令将 会被执行。

但是,在检查文件 foo.o 和 bar.o 的时间戳之前,它会往下查 找那些把 foo.o bar.o 做为目标文件的规则。它找到的关于 foo.o 的规则,该文件的依靠文件是foo.c, foo.h 和 bar.h 。 它从下面再找不到生成这些依靠文件的规则,它就开始检查磁碟 上这些依靠文件的时间戳。如果这些文件中任何一个的时间戳比 foo.o 的新,命令 'gcc -o foo.o foo.c' 将会执行,从而更新 文件 foo.o 。 

接下来对文件 bar.o 做类似的检查,依靠文件在这里是文件 bar.c 和 bar.h 

现在, make 回到‘myprog’的规则。如果刚才两个规则中的任 何一个被执行,myprog 就需要重建(因为其中一个 .o 档就会比 ‘myprog’新),因此连接命令将被执行。

希望到此,你可以看出使用 make 工具来建立程序的好处——前 一章中所有繁琐的检查步骤都由 make 替你做了:检查时间戳。 你的源码文件里一个简单改变都会造成那个文件被重新编译(因 为 .o 文件依靠 .c 文件),进而可执行文件被重新连接(因为 .o 文件被改变了)。其实真正的得益是在当你改变一个 header 档的时候——你不再需要记住那个源码文件依靠它,因为所有的 资料都在 makefile 里。 make 会很轻松的替你重新编译所有那 些因依靠这个 header 文件而改变了的源码文件,如有需要,再 进行重新连接。

当然,你要确定你在 makefile 中所写的规则是正确无误的,只 列出那些在源码文件中被 #include 的 header ……

2.2.2 编写 make 规则 (Rules) 

最明显的(也是最简单的)编写规则的方法是一个一个的查 看源码文件,把它们的目标文件做为目的,而C源码文件和被它 #include 的 header 档做为依靠文件。但是你也要把其它被这些 header 档 #include 的 header 档也列为依靠文件,还有那些被包括的文件所包括的文件……然后你会发现要对越来越多的文件 进行管理,然后你的头发开始脱落,你的脾气开始变坏,你的脸 色变成菜色,你走在路上开始跟电线杆子碰撞,终于你捣毁你的 电脑显示器,停止编程。到低有没有些容易点儿的方法呢?

当然有!向编译器要!在编译每一个源码文件的时候,它实在应 该知道应该包括什么样的 header 档。使用 gcc 的时候,用 -M 开关,它会为每一个你给它的C文件输出一个规则,把目标文件 做为目的,而这个C文件和所有应该被 #include 的 header文 件将做为依靠文件。注意这个规则会加入所有 header 文件,包 括被角括号(`<',`>')和双引号(`"')所包围的文件。其实我们可以 相当肯定系统 header 档(比如stdio.h, stdlib.h 等等)不会 被我们更改,如果你用 -MM 来代替 -M 传递给 gcc,那些用角括 号包围的 header 档将不会被包括。(这会节省一些编译时间)

由 gcc 输出的规则不会含有命令部分;你可以自己写入你的命令 或者什么也不写,而让 make 使用它的隐含的规则(参考下面的 2.2.4 节)。

2.2.3 Makefile 变量 

上面提到 makefiles 里主要包含一些规则。它们包含的其它的东 西是变量定义。

makefile 里的变量就像一个环境变量(environment variable)。 事实上,环境变量在make 过程中被解释成 make 的变量。这些 变量是大小写敏感的,一般使用大写字母。它们可以从几乎任何 地方被引用,也可以被用来做很多事情,比如: 

● 贮存一个文件名列表。在上面的例子里,生成可执行文件的 规则包含一些目标文件名做为依靠。在这个规则的命令行 里同样的那些文件被输送给 gcc 做为命令参数。如果在这 里使用一个变数来贮存所有的目标文件名,加入新的目标 文件会变的简单而且较不易出错。

● 贮存可执行文件名。如果你的项目被用在一个非 gcc 的系 统里,或者如果你想使用一个不同的编译器,你必须将所 有使用编译器的地方改成用新的编译器名。但是如果使用一 个变量来代替编译器名,那么你只需要改变一个地方,其 它所有地方的命令名就都改变了。 

● 贮存编译器旗标。假设你想给你所有的编译命令传递一组 相同的选项(例-Wall -O -g);如果你把这组选项存 入一个变量,那么你可以把这个变量放在所有呼叫编译器 的地方。而当你要改变选项的时候,你只需在一个地方改 变这个变量的内容。

要设定一个变量,你只要在一行的开始写下这个变量的名字,后 面跟一个 号,后面跟你要设定的这个变量的值。以后你要引用 这个变量,写一个 符号,后面是围在括号里的变量名。比如在 下面,我们把前面的 makefile 利用变量重写一遍:

=== makefile 开始 === 

OBJS = foo.o bar.o 

CC = gcc 

CFLAGS = -Wall -O -g 

myprog : $(OBJS) 

$(CC) $(OBJS) -o myprog 

foo.o : foo.c foo.h bar.h 

$(CC) $(CFLAGS) -c foo.c -o foo.o 

bar.o : bar.c bar.h 

$(CC) $(CFLAGS) -c bar.c -o bar.o 

=== makefile 结束 === 

还有一些设定好的内部变量,它们根据每一个规则内容定义。三个 比较有用的变量是$@, $< 和 $^ (这些变量不需要括号括住)。 $@ 扩展成当前规则的目的文件名, $< 扩展成依靠列表中的第 一个依靠文件,而 $^ 扩展成整个依靠的列表(除掉了里面所有重复的文件名)。利用这些变量,我们可以把上面的 makefile 写成:

=== makefile 开始 === 

OBJS = foo.o bar.o 

CC = gcc 

CFLAGS = -Wall -O -g 

myprog : $(OBJS) 

$(CC) $^ -o $@ 

foo.o : foo.c foo.h bar.h 

$(CC) $(CFLAGS) -c $< -o $@ 

bar.o : bar.c bar.h 

$(CC) $(CFLAGS) -c $< -o $@ 

=== makefile 结束 === 

你可以用变量做许多其它的事情,特别是当你把它们和函数混合 使用的时候。如果需要更进一步的了解,请参考 GNU Make 手册。 ('man make', 'man makefile') 

2.2.4 隐含规则 (Implicit Rules) 

请注意,在上面的例子里,几个产生 .o 文件的命令都是一样的。 都是从 .c 文件和相关文件里产生 .o 文件,这是一个标准的步 骤。其实 make 已经知道怎么做——它有一些叫做隐含规则的内 置的规则,这些规则告诉它当你没有给出某些命令的时候,应该 怎么办。

如果你把生成 foo.o 和 bar.o 的命令从它们的规则中删除, make 将会查找它的隐含规则,然后会找到一个适当的命令。它的命令会 使用一些变量,因此你可以按照你的想法来设定它:它使用变量 CC 做为编译器(象我们在前面的例子),并且传递变量CFLAGS (给 编译器,C++ 编译器用 CXXFLAGS ),CPPFLAGS ( 预 处理器旗标), TARGET_ARCH (现在不用考虑这个),然后它加 入旗标 '-c' ,后面跟变量$< (第一个依靠名),然后是旗 标 '-o' 跟变量 $@ (目的文件名)。一个C编译的具体命令将 会是:

$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ 

当然你可以按照你自己的需要来定义这些变量。这就是为什么用 gcc 的 -M 或 -MM 开关输出的码可以直接用在一个 makefile 里。 

2.2.5 假象目的 (Phony Targets) 

假设你的一个项目最后需要产生两个可执行文件。你的主要目标 是产生两个可执行文件,但这两个文件是相互独立的——如果一 个文件需要重建,并不影响另一个。你可以使用假象目的来 达到这种效果。一个假象目的跟一个正常的目的几乎是一样的, 只是这个目的文件是不存在的。因此, make 总是会假设它需要 被生成,当把它的依赖文件更新后,就会执行它的规则里的命令 行。 

如果在我们的 makefile 开始处输入:

all : exec1 exec2 

其中 exec1 和 exec2 是我们做为目的的两个可执行文件。 make 把这个 'all' 做为它的主要目的,每次执行时都会尝试把 'all' 更新。但既然这行规则里没有哪个命令来作用在一个叫 'all' 的 实际文件(事实上 all 并不会在磁碟上实际产生),所以这个规 则并不真的改变 'all' 的状态。可既然这个文件并不存在,所以 make 会尝试更新 all 规则,因此就检查它的依靠 exec1, exec2 是否需要更新,如果需要,就把它们更新,从而达到我们的目的。 

假象目的也可以用来描述一组非预设的动作。例如,你想把所有由 make 产生的文件删除,你可以在 makefile 里设立这样一个规则: 

veryclean : 

rm *.o 

rm myprog 

前提是没有其它的规则依靠这个 'veryclean' 目的,它将永远 不会被执行。但是,如果你明确的使用命令 'make veryclean' , make 会把这个目的做为它的主要目标,执行那些 rm 命令。

如果你的磁碟上存在一个叫 veryclean 文件,会发生什么事?这 时因为在这个规则里没有任何依靠文件,所以这个目的文件一定是 最新的了(所有的依靠文件都已经是最新的了),所以既使用户明 确命令 make 重新产生它,也不会有任何事情发生。解决方法是标 明所有的假象目的(用 .PHONY),这就告诉 make 不用检查它们 是否存在于磁碟上,也不用查找任何隐含规则,直接假设指定的目 的需要被更新。在 makefile里加入下面这行包含上面规则的规则: 

..PHONY : veryclean 就可以了。

注意,这是一个特殊的 make 规则,make 知道 .PHONY 是一个特殊目的, 
当然你可以在它的依靠里加入你想用的任何假象 目的,而 make 知道它们都是假象目的。 

2.2.6 函数 (Functions) 

makefile 里的函数跟它的变量很相似——使用的时候,你用一个 符号跟开括号,函数名,空格后跟一列由逗号分隔的参数,最后 用关括号结束。例如,在 GNU Make 里有一个叫 'wildcard' 的函 数,它有一个参数,功能是展开成一列所有符合由其参数描述的文 件名,文件间以空格间隔。你可以像下面所示使用这个命令:

SOURCES = $(wildcard *.c) 

这行会产生一个所有以 '.c' 结尾的文件的列表,然后存入变量 SOURCES 里。当然你不需要一定要把结果存入一个变量。

另一个有用的函数是 patsubst ( patten substitude, 匹配替 换的缩写)函数。它需要3个参数——第一个是一个需要匹配的 式样,第二个表示用什么来替换它,第三个是一个需要被处理的 由空格分隔的字列。例如,处理那个经过上面定义后的变量,

OBJS = $(patsubst %.c,%.o,$(SOURCES)) 

这行将处理所有在 SOURCES 字列中的字(一列文件名),如果它的 结尾是 '.c' ,就用 '.o' 把 '.c' 取代。注意这里的 符号将匹 配一个或多个字符,而它每次所匹配的字串叫做一个’(stem) 。 在第二个参数里, 被解读成用第一参数所匹配的那个柄。

2.2.7 一个比较有效的 makefile 

利用我们现在所学的,我们可以建立一个相当有效的 makefile 。 这个 makefile 可以完成大部分我们需要的依靠检查,不用做太大 的改变就可直接用在大多数的项目里。

首先我们需要一个基本的 makefile 来建我们的程序。我们可以让 它搜索当前目录,找到源码文件,并且假设它们都是属于我们的项 目的,放进一个叫 SOURCES 的变量。这里如果也包含所有的 *.cc 文件,也许会更保险,因为源码文件可能是 C++ 码的。

SOURCES = $(wildcard *.c *.cc) 

利用 patsubst ,我们可以由源码文件名产生目标文件名,我们需 要编译出这些目标文件。如果我们的源码文件既有 .c 文件,也有 .cc 文件,我们需要使用相嵌的patsubst 函数呼叫:

OBJS = $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(SOURCES))) 

最里面一层 patsubst 的呼叫会对 .cc 文件进行后缀替代,产生的结 果被外层的patsubst 呼叫处理,进行对 .c 文件后缀的替代。 

现在我们可以设立一个规则来建可执行文件:

myprog : $(OBJS) 

gcc -o myprog $(OBJS) 

进一步的规则不一定需要, gcc 已经知道怎么去生成目标文件 (object files) 。下面我们可以设定产生依靠信息的规则: 

depends : $(SOURCES) 

gcc -M $(SOURCES) > depends 

在这里如果一个叫 'depends' 的文件不存在,或任何一个源码文件 比一个已存在的 depends 文件新,那么一个 depends 文件会被生 成。depends 文件将会含有由 gcc 产生的关于源码文件的规则(注 意 -M 开关)。现在我们要让 make 把这些规则当做makefile 档 的一部分。这里使用的技巧很像 语言中的 #include 系统——我 们要求 make 把这个文件 include 到 makefile 里,如下: 

include depends 

GNU Make 看到这个,检查 'depends' 目的是否更新了,如果没有, 它用我们给它的命令重新产生 depends 档。然后它会把这组(新) 规则包含进来,继续处理最终目标'myprog' 。当看到有关 myprog 的规则,它会检查所有的目标文件是否更新——利用depends 文件 里的规则,当然这些规则现在已经是更新过的了。 

这个系统其实效率很低,因为每当一个源码文件被改动,所有的源码 文件都要被预处理以产生一个新的 'depends' 文件。而且它也不是 100% 的安全,这是因为当一个header 档被改动,依靠信息并不会 被更新。但就基本工作来说,它也算相当有用的了。

2.2.8 一个更好的 makefile

这是一个我为我大多数项目设计的 makefile 。它应该可以不需要修 改的用在大部分项目里。我主要把它用在 djgpp 上,那是一个 DOS 版的 gcc 编译器。因此你可以看到执行的命令名、 'alleg' 程序包、 和 RM -F 变量都反映了这一点。

=== makefile 开始 === 

###################################### 

# Generic makefile 

# by George Foot 

# email: george.foot@merton.ox.ac.uk 

# Copyright (c) 1997 George Foot 

# All rights reserved. 

保留所有版权 

# No warranty, no liability; 

# you use this at your own risk. 

没保险,不负责 

你要用这个,你自己担风险 

# You are free to modify and 

# distribute this without giving 

# credit to the original author. 

你可以随便更改和散发这个文件 

而不需要给原作者什么荣誉。 

(你好意思?) 

###################################### 

### Customising 

用户设定 

# Adjust the following if necessary; EXECUTABLE is the target 

# executable's filename, and LIBS is a list of libraries to link in 

# (e.g. alleg, stdcx, iostr, etc). You can override these on make's 

# command line of course, if you prefer to do it that way. 

如果需要,调整下面的东西。 EXECUTABLE 是目标的可执行文件名, LIBS 

是一个需要连接的程序包列表(例如 alleg, stdcx, iostr 等等)。当然你 
可以在 make 的命令行覆盖它们,你愿意就没问题。 

EXECUTABLE := mushroom.exe 

LIBS := alleg 

# Now alter any implicit rules' variables if you like, e.g.: 

现在来改变任何你想改动的隐含规则中的变量,例如 

CFLAGS := -g -Wall -O3 -m486 

CXXFLAGS := $(CFLAGS) 

# The next bit checks to see whether rm is in your djgpp bin 

# directory; if not it uses del instead, but this can cause (harmless) 

# `File not found' error messages. If you are not using DOS at all, 

# set the variable to something which will unquestioningly remove 

# files. 

下面先检查你的 djgpp 命令目录下有没有 rm 命令,如果没有,我们使用 

# del 命令来代替,但有可能给我们 'File not found' 这个错误信息,这没 

什么大碍。如果你不是用 DOS ,把它设定成一个删文件而不废话的命令。 

(其实这一步在 UNIX 类的系统上是多余的,只是方便 DOS 用户。 UNIX 

用户可以删除这5行命令。) 

ifneq ($(wildcard $(DJDIR)/bin/rm.exe),) 

RM-F := rm -f 

else 

RM-F := del 

endif 

# You shouldn't need to change anything below this point. 

从这里开始,你应该不需要改动任何东西。(我是不太相信,太NB了!) 

SOURCE := $(wildcard *.c) $(wildcard *.cc) 

OBJS := $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(SOURCE))) 

DEPS := $(patsubst %.o,%.d,$(OBJS)) 

MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS)) 

MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.c,$(MISSING_DEPS)) \ 

$(patsubst %.d,%.cc,$(MISSING_DEPS))) 

CPPFLAGS += -MD 

..PHONY : everything deps objs clean veryclean rebuild 

everything : $(EXECUTABLE) 

deps : $(DEPS) 

objs : $(OBJS) 

clean : 

@$(RM-F) *.o 

@$(RM-F) *.d 

veryclean: clean 

@$(RM-F) $(EXECUTABLE) 

rebuild: veryclean everything 

ifneq ($(MISSING_DEPS),) 

$(MISSING_DEPS) : 

@$(RM-F) $(patsubst %.d,%.o,$@) 

endif 

-include $(DEPS) 

$(EXECUTABLE) : $(OBJS) 

gcc -o $(EXECUTABLE) $(OBJS) $(addprefix -l,$(LIBS)) 

=== makefile 结束 === 

有几个地方值得解释一下的。首先,我在定义大部分变量的时候使 用的是 := 而不是符号。它的作用是立即把定义中参考到的函 数和变量都展开了。如果使用 的话,函数和变量参考会留在那 儿,就是说改变一个变量的值会导致其它变量的值也被改变。例 如: 

A = foo 

B = $(A) 

现在 是 $(A) ,而 $(A) 是 'foo' 。 

A = bar 

现在 仍然是 $(A) ,但它的值已随着变成 'bar' 了。 

B := $(A) 

现在 的值是 'bar' 。 

A = foo 

# B 的值仍然是 'bar' 。 

make 会忽略在 符号后面直到那一行结束的所有文字。 

ifneg...else...endif 系统是 makefile 里让某一部分码有条件的 失效/有效的工具。 ifeq 使用两个参数,如果它们相同,它把直 到 else (或者 endif ,如果没有else 的话)的一段码加进 makefile 里;如果不同,把 else 到 endif 间的一段码加入 makefile (如果有 else )。 ifneq 的用法刚好相反。 

'filter-out' 函数使用两个用空格分开的列表,它把第二列表中所 有的存在于第一列表中的项目删除。我用它来处理 DEPS 列表,把所 有已经存在的项目都删除,而只保留缺少的那些。 

我前面说过, CPPFLAGS 存有用于隐含规则中传给预处理器的一些 旗标。而 -MD 开关类似 -M 开关,但是从源码文件 .c 或 .cc 中 形成的文件名是使用后缀 .d 的(这就解释了我形成 DEPS 变量的 步骤)。DEPS 里提到的文件后来用 '-include' 加进了makefile 里,它隐藏了所有因文件不存在而产生的错误信息。 

如果任何依靠文件不存在, makefile 会把相应的 .o 文件从磁碟 上删除,从而使得make 重建它。因为 CPPFLAGS 指定了 -MD , 它的 .d 文件也被重新产生。

最后, 'addprefix' 函数把第二个参数列表的每一项前缀上第一 个参数值。 

这个 makefile 的那些目的是(这些目的可以传给 make 的命令行 来直接选用):

everything:(预设) 更新主要的可执行程序,并且为每一个 源码文件生成或更新一个 '.d' 文件和一个 '.o' 文件。

deps: 只是为每一个源码程序产生或更新一个 '.d' 文件。 

objs: 为每一个源码程序生成或更新 '.d' 文件和目标文件。 

clean: 删除所有中介/依靠文件( *.d 和 *.o )。 

veryclean: 做 `clean' 和删除可执行文件。 

rebuild: 先做 `veryclean' 然后 `everything' ;既完全重建。 

除了预设的 everything 以外,这里头只有 clean , veryclean , 和 rebuild 对用户是有意义的。 

我还没有发现当给出一个源码文件的目录,这个 makefile 会失败的 情况,除非依靠文件被弄乱。如果这种弄乱的情况发生了,只要输入 `make clean' ,所有的目标文件和依靠文件会被删除,问题就应该 被解决了。当然,最好不要把它们弄乱。如果你发现在某种情况下这 个 makefile 文件不能完成它的工作,请告诉我,我会把它整好的。

2.3 总结

~~~~~~~~~~~~~~~ 

我希望这篇文章足够详细的解释了多文件项目是怎么运作的,也说明了 怎样安全而合理的使用它。到此,你应该可以轻松的利用 GNU Make 工 具来管理小型的项目,如果你完全理解了后面几个部分的话,这些对于 你来说应该没什么困难。

GNU Make 是一件强大的工具,虽然它主要是用来建立程序,它还有很多 别的用处。如果想要知道更多有关这个工具的知识,它的句法,函数, 和许多别的特点,你应该参看它的参考文件 (info pages, 别的 GNU 工具也一样,看它们的 info pages. )。 

C Scene 官方网站: http://cscene.differnet.org 

C Scene 官方电邮: cscene@mindless.com 

This page is Copyright ? 1997 By C Scene. All Rights Reserved --------------------------------------------------------------------------------

3GUN gcc编程

本节学习GNU推出的Linux系统下C编译器----gcc,主要介绍这种编译器的基本原理和使用方法,以及编译过程中所产生的错误的原因及对策。 
3.1gcc简介 
    Linux系统下的gccGNU C Compiler)是GNU推出的功能强大、性能优越的多平台编译器,是GNU的代表作品之一。gcc是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%~30%。 
    gcc编译器能将CC++语言源程序、汇程式化序和目标程序编译、连接成可执行文件,如果没有给出可执行文件的名字,gcc将生成一个名为a.out的文件。在Linux系统中,可执行文件没有统一的后缀,系统从文件的属性来区分可执行文件和不可执行文件。而gcc则通过后缀来区别输入文件的类别,下面我们来介绍gcc所遵循的部分约定规则。 
    .c为后缀的文件,C语言源代码文件; 
    .a为后缀的文件,是由目标文件构成的档案库文件; 
    .C.cc.cxx 为后缀的文件,是C++源代码文件; 
    .h为后缀的文件,是程序所包含的头文件; 
    .i 为后缀的文件,是已经预处理过的C源代码文件; 
    .ii为后缀的文件,是已经预处理过的C++源代码文件; 
    .m为后缀的文件,是Objective-C源代码文件; 
    .o为后缀的文件,是编译后的目标文件; 
    .s为后缀的文件,是汇编语言源代码文件; 
    .S为后缀的文件,是经过预编译的汇编语言源代码文件。 
3.2gcc的执行过程 
   虽然我们称gccC语言的编译器,但使用gccC语言源代码文件生成可执行文件的过程不仅仅是编译的过程,而是要经历四个相互关联的步骤预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编(Assembly)和连接(Linking)。 
   命令gcc首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(include)、预编译语句(如宏定义define)进行分析。接着调用cc1进行编译,这个阶段根据输入文件生成以.o为后缀的目标文件。汇编过程是针对汇编语言的步骤,调用as进行工作,一般来讲,.S为后缀的汇编语言源代码文件和汇编、.s为后缀的汇编语言文件经过预编译和汇编之后都生成以.o为后缀的目标文件。当所有的目标文件都生成之后,gcc就调用ld来完成最后的关键性工作,这个阶段就是连接。在连接阶段,所有的目标文件被安排在可执行程序中的恰当的位置,同时,该程序所调用到的库函数也从各自所在的档案库中连到合适的地方。 
3.3gcc的基本用法和选项 
   在使用gcc编译器的时候,我们必须给出一系列必要的调用参数和文件名称。gcc编译器的调用参数大约有100多个,其中多数参数我们可能根本就用不到,这里只介绍其中最基本、最常用的参数。 
   gcc最基本的用法是

gcc

使用权限:所有使用者 

使用方式:gcc [options] [filenames]  

说明:在使用gcc编译器的时候,我们必须给出一系列必要的调用参数和文件名称。其中options就是编译器所需要的参数,filenames给出相关的文件名称。 

参数: 

l -c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。 

l -o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。  

l -g,产生符号调试工具(GNUgdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项。

l -O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。

l -O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。

l -Idirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。C程序中的头文件包含两种情况

A#include 
B#include “myinc.h” 

其中,A类使用尖括号(< >)B类使用双引号(“ ”)。对于A类,预处理程序cpp在系统预设包含文件目录(/usr/include)中搜寻相应的文件,而对于B类,cpp在当前目录中搜寻头文件,这个选项的作用是告诉cpp,如果在当前目录中没有找到需要的文件,就到指定的dirname目录中去寻找。在程序设计中,如果我们需要的这种包含文件分别分布在不同的目录中,就需要逐个使用-I选项给出搜索路径。 

l -Ldirname,将dirname所指出的目录加入到程序函数档案库文件的目录列表中,是在连接过程中使用的参数。在预设状态下,连接程序ld在系统的预设路径中(/usr/lib)寻找所需要的档案库文件,这个选项告诉连接程序,首先到-L指定的目录中去寻找,然后到系统预设路径中寻找,如果函数库存放在多个目录下,就需要依次使用这个选项,给出相应的存放目录。

l -lname,在连接时,装载名字为“libname.a”的函数库,该函数库位于系统预设的目录或者由-L选项确定的目录下。例如,-lm表示连接名为“libm.a”的数学函数库。 

范例: 

l 假定我们有一个程序名为test.cC语言源代码文件,要生成一个可执行文件,最简单的办法就是∶ 
gcc test.c 
这时,预编译、编译连接一次完成,生成一个系统预设的名为a.out的可执行文件,对于稍为复杂的情况,比如有多个源代码文件、需要连接档案库或者有其他比较特别的要求,就要给定适当的调用选项参数。cat -b textfile1 textfile2 >> textfile3 把 textfile1 和 textfile2 的档案内容加上行号(空白行不加)之后将内容附加到 textfile3 

l 再看一个简单的例子。 
整个源代码程序由两个文件testmain.c testsub.c组成,程序中使用了系统提供的数学库,同时希望给出的可执行文件为test,这时的编译命令可以是∶ 
gcc testmain.c testsub.c □lm □o test 
其中,-lm表示连接系统的数学库libm.a,这个过程可以用图12-1框图描述。 

gcc的错误类型及对策 
gcc编译器如果发现源程序中有错误,就无法继续进行,也无法生成最终的可执行文件。为了便于修改,gcc给出错误资讯,我们必须对这些错误资讯逐个进行分析、处理,并修改相应的语言,才能保证源代码的正确编译连接。gcc给出的错误资讯一般可以分为四大类,下面我们分别讨论其产生的原因和对策。 
  第一类∶C语法错误 
错误资讯文件source.c中第n行有语法错误(syntex errror)。这种类型的错误,一般都是C语言的语法错误,应该仔细检查源代码文件中第n行及该行之前的程序,有时也需要对该文件所包含的头文件进行检查。有些情况下,一个很简单的语法错误,gcc会给出一大堆错误,我们最主要的是要保持清醒的头脑,不要被其吓倒,必要的时候再参考一下C语言的基本教材。 
  第二类头文件错误 
错误资讯找不到头文件head.h(Can not find include file head.h)。这类错误是源代码文件中的包含头文件有问题,可能的原因有头文件名错误、指定的头文件所在目录名错误等,也可能是错误地使用了双引号和尖括号。 
  第三类档案库错误 
错误资讯连接程序找不到所需的函数库,例如∶ 
ld: -lm: No such file or directory 

这类错误是与目标文件相连接的函数库有错误,可能的原因是函数库名错误、指定的函数库所在目录名称错误等,检查的方法是使用find命令在可能的目录中寻找相应的函数库名,确定档案库及目录的名称并修改程序中及编译选项中的名称。 
  第四类未定义符号 
错误资讯有未定义的符号(Undefined symbol)。这类错误是在连接过程中出现的,可能有两种原因一是使用者自己定义的函数或者全局变量所在源代码文件,没有被编译、连接,或者干脆还没有定义,这需要使用者根据实际情况修改源程序,给出全局变量或者函数的定义体;二是未定义的符号是一个标准的库函数,在源程序中使用了该库函数,而连接过程中还没有给定相应的函数库的名称,或者是该档案库的目录名称有问题,这时需要使用档案库维护命令ar检查我们需要的库函数到底位于哪一个函数库中,确定之后,修改gcc连接选项中的-l-L项。 
   排除编译、连接过程中的错误,应该说这只是程序设计中最简单、最基本的一个步骤,可以说只是开了个头。这个过程中的错误,只是我们在使用C语言描述一个算法中所产生的错误,是比较容易排除的。我们写一个程序,到编译、连接通过为止,应该说刚刚开始,程序在运行过程中所出现的问题,是算法设计有问题,说得更玄点是对问题的认识和理解不够,还需要更加深入地测试、调试和修改。一个程序,稍为复杂的程序,往往要经过多次的编译、连接和测试、修改。下面我们学习的程序维护、调试工具和版本维护就是在程序调试、测试过程中使用的,用来解决调测阶段所出现的问

4linux C 编程

4.1前言 

Linux的发行版中包含了很多软件开发工具它们中的很多是用于 和 C++应用程序开发的本文介绍了在 Linux 下能用于 应用程序开发和调试的工具本文的主旨是介绍如何在 Linux 下使用 编译器和其他 编程工具而非 语言编程的教程在本文中你将学到以下知识

l 什么是 

l GNU C 编译器 

l 用 gdb 来调试GCC应用程序 

你也能看到随 Linux 发行的其他有用的 编程工具这些工具包括源程序美化程序(pretty print programs), 附加的调试工具函数原型自动生成工具(automatic function prototypers). -------------------------------------------------------------------------------- 

注意源程序美化程序(pretty print programs)自动帮你格式化源代码产生始终如一的缩进格式. -------------------------------------------------------------------------------- 

1. 什么是 C? 

是一种在 UNIX 操作系统的早期就被广泛使用的通用编程语言它最早是由贝尔实验室的 Dennis Ritchie 为了 UNIX 的辅助开发而写的开始时 UNIX 是用汇编语言和一种叫 的语言编写的从那时候起, C 就成为世界上使用最广泛计算机语言

能在编程领域里得到如此广泛支持的原因有以下一些

l 它是一种非常通用的语言几乎你所能想到的任何一种计算机上都有至少一种能用的 编译器并且它的语法和函数库在不同的平台上都是统一的这个特性对开发者来说很有吸引力

l 用 写的程序执行速度很快

l C 是所有版本的UNIX上的系统语言

在过去的二十年中有了很大的发展80年代末期美国国家标准协会(American National Standards Institute)发布了一个被称为 ANSI C 的 语言标准.这更加保证了将来在不同平台上的 的一致性80年代还出现了一种 的面向对象的扩展称为 C++. C++ 将在另一篇文章 "C++ 编程"中描述

l Linux 上可用的 编译器是 GNU C 编译器它建立在自由软件基金会的编程许可证的基础上因此可以自由发布你能在 Linux 的发行光盘上找到它

2GNU C 编译器 

随 Slackware Linux 发行的 GNU C 编译器(GCC)是一个全功能的 ANSI C 兼容编译器如果你熟悉其他操作系统或硬件平台上的一种 编译器你将能很快地掌握 GCC. 本节将介绍如何使用 GCC 和一些 GCC 编译器最常用的选项

3使用 GCC 

通常后跟一些选项和文件名来使用 GCC 编译器. gcc 命令的基本用法如下

gcc [options] [filenames] 

命令行选项指定的操作将在命令行上每个给出的文件上执行下一小节将叙述一些你会最常用到的选项

4.2GCC 选项 

GCC 有超过100个的编译选项可用这些选项中的许多你可能永远都不会用到但一些主要的选项将会频繁用到很多的 GCC 选项包括一个以上的字符因此你必须为每个选项指定各自的连字符并且就象大多数 Linux 命令一样你不能在一个单独的连字符后跟一组选项例如下面的两个命令是不同的

gcc -p -g test.c 

gcc -pg test.c

第一条命令告诉 GCC 编译 test.c 时为 prof 命令建立剖析(profile)信息并且把调试信息加入到可执行的文件里第二条命令只告诉 GCC 为 gprof 命令建立剖析信息

当你不用任何选项编译一个程序时, GCC 将会建立(假定编译成功)一个名为 a.out 的可执行文件例如下面的命令将在当前目录下产生一个叫 a.out 的文件:

gcc test.c 

你能用 -o 编译选项来为将产生的可执行文件指定一个文件名来代替 a.out. 例如将一个叫 count.c 的 程序编译为名叫 count 的可执行文件你将输入下面的命令

gcc -o count count.c -------------------------------------------------------------------------------- 

注意当你使用 -o 选项时, -o 后面必须跟一个文件名. -------------------------------------------------------------------------------- 

GCC 同样有指定编译器处理多少的编译选项. -c 选项告诉 GCC 仅把源代码编译为目标代码而跳过汇编和连接的步骤这个选项使用的非常频繁因为它使得编译多个 程序时速度更快并且更易于管理缺省时 GCC 建立的目标代码文件有一个 .o 的扩展名

-S 编译选项告诉 GCC 在为 代码产生了汇编语言文件后停止编译. GCC 产生的汇编语言文件的缺省扩展名是 .s . -E 选项指示编译器仅对输入文件进行预处理当这个选项被使用时预处理器的输出被送到标准输出而不是储存在文件里

4.3优 化 选 项 

当你用 GCC 编译 代码时它会试着用最少的时间完成编译并且使编译后的代码易于调试易于调试意味着编译后的代码与源代码有同样的执行次序编译后的代码没有经过优化有很多选项可用于告诉 GCC 在耗费更多编译时间和牺牲易调试性的基础上产生更小更快的可执行文件这些选项中最典型的是-O 和 -O2 选项

-O 选项告诉 GCC 对源代码进行基本优化这些优化在大多数情况下都会使程序执行的更快. -O2 选项告诉 GCC 产生尽可能小和尽可能快的代码. -O2 选项将使编译的速度比使用 -O 时慢但通常产生的代码执行速度会更快

除了 -O 和 -O2 优化选项外还有一些低级选项用于产生更快的代码这些选项非常的特殊而且最好只有当你完全理解这些选项将会对编译后的代码产生什么样的效果时再去使用这些选项的详细描述请参考 GCC 的指南页在命令行上键入 man gcc

5gdb

   gdbGUNC/C++程序调试器,它允许您在程序运行时观察程序的 内部结构和内存的使用情况。

   利用gdb,您可以调试一个可执行的程序,也可以检查一个因程序异常终止而产生的core文件或者一个进程相连。

  要使gdb正常工作,您必须在编译时打开-g项,将调试信息包含到目标文件中。调试信息描述了程序中每个变量的类型和可执行文件的地址映射及源代码的行号,在源文件通机器代码之间建立关联。注意:如果您使用gdb调试一个由-g

-o选项产生的程序时,千万记住编译器为了优化代码会重新调整你的程序,造成运行与你的设想不同;为此,建议您调试时不要使用-o选项。

   Gdb命令的格式为:

gdb [选项1] [参数1][ 选项2] …….

其中,选项和参数均为可选项。

启动gdb后,您可以使用gdb提供的内部命令来调试程序了。

掌握gdb命令的关键,就是熟悉它的命令行选项及参数和它的内部命令。

 5.1 gdb的命令行选项和参数

选项和参数区别在于选项以标志符‘-’开头,如-c;而参数前则没有任何标志。Gdb的选项和参数主要有:

1. 文件类选项和参数:指与被调试程序相关的选项和参数。

2. 模式类选项和参数:指于gdb运行模式相关的选项和参数。

5.1.1 文件类选项和参数

[参数]: <program>

[格式]:  gdb  <program>

[功能]:  在启动gdb的同时装入名为program 的文件名。

[示例]: gdb hello

[参数]: <program>  core

[格式]: gdb  <program> core

[功能]: 在启动gdb的同时为程序program指定一个core文件。

[示例]gdb hello core

[参数]: <program>  <进程号>

[格式]gdb   <program>  <进程号>

[功能]:在启动gdb的同时,为程序program指定进程号,并将gdb同进程相连。

[示例]gdb hello 123

5.2 gdb的内部命令

  这些命令只在启动了gdb之后才能使用。

5.2.1 调试类命令

 [命令]file  <program>

[功能]:装入想要调试的可执行程序。

 [功能]list

[示例]:列出产生可执行程序的源文件的部分代码;默认情况下,每次列出10行源代码。

调试器的基本功能就是让程序在某些条件下停止运行,使您可以改变程序 的运行方式,然后安装你的设定继续执行程序,创造条件是你能够检查出当程序报错时到底执行了那些具体的操作。在gdb内部,程序会由于各种原因而暂时停止,比如:一个信号,一个断点或由于你使用了step命令等。

断点的作用是当你程序运行到断点时,无论它在做什么都要停下来。对于每个断点您都设置一些更高级的信息以决定断点在什么时候起作用。你可以使用break命令在你的程序中设置断点。

[命令]break  <function>

[功能]:在程序中function函数的定义处设定断点。如果程序使用的是允许函数重载的语言(入c++)时,有可能在几个重载的函数上同时设置断点。

[命令]break  <line-num>

[功能]:在行号为line-num的行上设置断点;程序在运行到此行之前停止。

[命令]break  <filename>:<line-num>

[功能]:在文件名为filename的源文件的第line-num行设置断点。

[命令]break  <filename>:<function>

[功能]:在文件名为filename源文件的function函数上设置断点。

[说明]:当您在多个文件中都含有function函数使用此命令。

当一个断点完成它的使命后,您需要把它从程序中删除:否则你的程序还会在相同的地方停止,给你造成麻烦。使用clear 命令删除指定位置的断点,使用delete删除相应断点号的断点。

[命令]clear <function>

[功能]: 删除名为function函数上的断点。

[命令]clear <filename> : <function>

[功能]: 删除文件filename中名为function函数上的断点。

[命令]clear <line-num>

[功能]: 删除行号line-num上的断点。

[命令]clear <filename> : <line-num>

[功能]: 删除文件filename 中行号line-num上的断点。

[命令]delete

[功能]: 删除程序中所有的断点。

[命令]delete <断点号>

[功能]: 删除指定的断点。

观察点是一种特殊的断点,它们在某个表达式的值发生变化时,停止程序的运行。除了设置观察点的命令不同于断点外,您可以像对普通断点一样对观察点进行操作。观察点在使用时开销比较大,但其查找错误的能力很强,特别是当你不能确定程序的错误出现在什么地方时。

[命令]watch <express>

[功能]:此命令设置expression表达式作为观察点。Gdb将这个表达式加入到程序中并监视程序的运行,在表达式的值发生改变时,gdb停止程序的运行。

[命令]step

[功能]:  每次执行一行代码,且进入函数的内部。

[命令]step  <num>

[功能]:  每次执行num行代码,且进入函数的内部。

[命令]next

[功能]:  每次执行一行代码,且不进入函数的内部。

[命令]next <num>

[功能]:  每次执行num行代码,且不进入函数的内部。

[命令]continue

[功能]:  继续执行被中断的程序。

[命令]kill ctrl+c

[功能]:  结束gdb内部命令的运行,但不退出gdb,而是返回gdb的命令模式。

[命令]quit / ctrl +d

[功能]: 退出gdb.

以上是有关linux的一些常用命令。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值