第一章 命令
一、文件基本操作
(1)文件列表(ls、chmod、chown)
显示文件列表(ls -l)-l是参数
ls命令:显示当前目录下的所有的文件
ls -l:显示total:文件夹的字节数(以kb为单位)
第1列:显示文件的类型和文件权限
① 前缀(首字符):
d表示目录文件(可理解为文件夹); -表示普通文件;
c表示字符设备文件; b表示块设备文件;
l表示链接文件; p表示管道文件
②除前缀外每三个一组,表示文件访问权限;
第一组表示文件属主的访问权限;
第二组表示组用户成员的访问权限;
第三组表示其他用户的访问权限;
r表示可读;w表示可写;x表示可执行
③修改文件权限:chmod 权限位 文件名
权限位:三个位置rwx对应二进制数,1表示有,0表示没有,比如rwx对应二进制数7;
第2列:显示文件的链接数
第3列:文件的属主
第4列:文件的组用户
①改变文件的属主及组用户
chown(改变属主)——格式:chown 属主名 文件名——只有超级用户可以修改
chgrp(改变组用户)——格式:chgrp 组用户名 文件名
第5列:文件的字节数
第6~8列:文件的修改时间
第9列(尾列):文件的文件名
(2)文件链接(ln、ln -s)
ln:硬链接(格式:ln 链接文件 被链接文件)—— 将文件放到硬盘上同样的位置;
echo “1111” > pp——将1111写入到pp文件中,>是重定向,覆盖pp
符号链接(软链接):ln -s
(3)显示文件(cat、more)
① cat 文件名: 直接显示全部,当文件内容过多的时候会导致上面的内容看不见;
② more 文件名: 逐屏显示,按空格往下一行一行显示;
③ less 文件名: 上下翻页,pgup和pgdn目录;
④ 文件头:head 文件名,tail 文件名;
(4)文件目录(cd、pwd、mkdir)
cd:切换目录
pwd:
mkdir:创建目录
man:用户手册
(5)拷贝文件(cp、cp-r)
① cp 被拷贝文件 拷贝目的目录(将文件pp拷贝到qq中——cp pp qq)
② cp -r qq we(拷贝目录qq及其中的所有文件和子目录拷贝到看目录we中)
(6)文件改名及移动文件(mv)
文件改名:mv pp oo(将文件名pp改为oo)——改名的时候oo这个文件名在目录中是没有的
文件移动:mv oo we(将文件oo移动到we中)
(7)删除文件及目录(rm、rm -r、rmdir)
① rm 要删除的文件名
② rmdir 要删除的目录名(需要时空目录);
③ rm -r 要删除的目录和其中的子目录
(8)查找及匹配文件内容(Find、grep)
查找文件:
find 搜索的起点目录 搜索类型 搜索内容 -print
比如:find . -name pc.c -print
(从当前目录开始搜索,搜索文件名为pc.c的目录并将路径打印出来)
其中搜索内容可以使用通配符,比如p*c就是以p开头以c结尾的文件
匹配字符串
grep include pc.c ——在文件pc.c中查找字符串“include”
组合命令:
find . -name pc.c -print|xargs grep include
“|xargs”的作用是:将“|”前命令的执行结果,作为输入参数传递给“|”后的命令
二、文件系统:mount、umount、df指令
mount命令:显示当前系统中的各个文件系统及其挂载的目录
对于显示的 /dev/sda2 on / type ext4 (rw) 解读:
/dev/sda2【文件系统——对应硬盘的第二个分区】 on /【根目录】 type ext4【文件系统类型】 (rw)【可读可写】
mount 文件系统 挂载目录(比如:mount /dev/sdb /home/stu/qq)
nmount 文件系统(卸载下来)
三、文件归档压缩:tar、gzip、bzip2指令
(1)gzip,压缩成.gz文件,解压命令是gzip -d或者gunzip
(2)bzip2,压缩成bz2文件
四、进程:ps、pstree、kill指令
ps:显示当前用户在当前终端上运行的进程
ps -ef:显示整个系统上所有的进程
UID——用户ID; PID——进程ID; PPID——父进程ID; C——CPU占用率;
STIME——进程开始时间; TTY——进程运行的终端号; TIME——进程运行时间;
CMD——命令名
ps -aux:显示的更加丰富
ps -t pts/1: 在pts/1这个终端上运行的进程
kill -9 2706: 杀死对应的进程
第二章 vi编译器
一、两种模式切换、存盘等(命令格式:vi 文件名+回车)
①命令模式下:
键入“delete”或者“x”删除光标位置的字符;
返回“Esc”返回命令模式;
键入“w”进行存盘;
键入“q”进行退出,键入“wq”进行存盘退出。
②编辑模式下:
键入小写的i或者a进入编辑模式;
进入之后键入“Esc”返回命令模式。
二、vi下的快捷命令(在命令模式下)
① 键入小写“o”在光标所在行下面再启一个新行,且进入编辑状态;
② 键入大写“O”在光标所在行上面再启一个新行,且进入编辑状态
③ 键入“yy”,光标所在行将被复制,将光标移动到某一行;
键入“p”被复制的行将粘贴到这一行下面。
④ 键入“nyy”,光标所在连续n行将被复制,将光标移动到某一行;
键入“p”被复制的n行将粘贴到这一行下面。
⑤ 键入“ndd”,光标所在行之后的连续n行将被删除;
键入“p”被删除的n行将粘贴到这一行下面。
⑥ 键入“2yw”,光标所在位置的连续2个单词将被复制,
键入“p”,被复制的两个单词将被粘贴到新位置
⑦ 键入“/am”,在当前文本中匹配字符串“xxx”;
键入“n”在匹配到的字符串中从上往下移动,键入“N”在匹配的字符串中从下往上移动;
键入“ns”,然后键入所想替换的字符“xxx”可进行字符的替换
(n表示要替换的字符的数量,比如替换good就键入4s)
⑧ 键入“.”,在当前光标所在的位置重复上一条命令
⑨ 进行全文替换的操作:开始行,结束行s/被替换的字符/替换字符/g
举例:1,$s/good/better/g
1表示从第一行开始;
$在vi中表示最后一行;
s是替换的标志; g表示全文替换。
/good/better/表示将good替换成better;
第三章 Linux Shell程序设计
一、第一个简单的shell脚本
进入vi编辑器,在编辑模式下写入clear(清屏)命令,存盘并退出。
当直接运行pp文件的时候,会显示查找不到,这是因为linux不认为当前目录是可以执行的目录,所有的可执行文件都会搜索相应的环境变量(用grep PATH命令可以显示出可以执行可执行文件的目录),如下图所示。
若想让文件执行,有3种方式:
① 用shell读入pp当中的命令并执行:sh pp;
② 先赋予pp可执行权限,再执行:chmod 777 pp;./pp;
③ 切换成超级用户,再拷贝pp到可执行目录下:cp pp /usr/bin;
二、shell中的变量
shell变量的三种定义方法:
① a=123(直接赋值)
② read a(从键盘输入)
③ 往下见for循环部分foo循环变量的使用;
在linux中没有类型,所有的变量都默认为字符串,在变量前面加上“$”就引用这个变量的值。
echo $a 命令和 echo “$” 命令没有区别,都是输出变量a的值;但是 echo ‘$a’ 输出就是单引号内的值;
三、条件分支语句
(1)if语句:
使用一对“[]”构成条件分支判断(使用test代替[]也是可以的)
①单分支条件格式
if [ 条件分支判断语句 ]; then(注意then前面有一个空格和一个分号)
执行语句1
else
执行语句2
fi
②双分支条件格式
if [ 条件分支判断语句 ]
then
执行语句1
else
执行语句2
fi
③多分支条件分支语句
if [ 条件分支判断语句1 ]
then
执行语句1
elif [ 条件分支判断语句2 ]; then
执行语句2
else
执行语句3
fi
判断一个文件是否存在以及相关属性:
如下,-f表示判断一个文件是否存在,-d表示判断一个文件是否属于目录文件
(2)case语句及正则表达式
在case语句当中,每个分支的后面有单个括号“)”,在每条语句的后面有两个分号“;;”,每个case语句和esac语句是匹配的
格式:
case “$变量” in
“值1” ) 执行语句1;;
“值2” ) 执行语句2;;
“值3” ) 执行语句3;;
esac
正则表达式:使用方括号括起来的内容,如 [nN] | [nN][oO] 就表示N/n或者nN其中一个和oO其中一个的任意组合;
四、循环语句
(1)for循环
如下图:foo是循环变量,是shell变量的第三种定义方式。in后面三个用空格隔开的值指的是每次循环foo所取的值,第一次循环foo取值bar,第二次循环foo取值fud,第三次循环foo取值43;
如下图:
file是循环变量,ls f* 的执行结果是目录中所有以f开头的文件名,文件名之间会用空格隔开。
以下两种方式 $(···) 和 `···` 的含义是一样的
(2)while循环
“$foo” -le 20表示的是判断变量foo是否小于等于20,-le表示小于等于。
使用的时候一定要注意 foo=$(($foo+1))有两次 “()” 。
五、函数与参数
(1)函数:fun(){ }
对于以下函数的解释:
第一行:foo()后面的 “()” 表示foo是一个函数,{}中的内容是函数体;
第七行:foo是指主程序中调用foo执行;
第三行:$1和第七行的$1含义也不同,如下图可知。如果想用第七行的$1则需要调用函数的$2参数。
foo() {
echo "Function foo is executing"
echo $1
}
echo "script starting"
foo "abc" $1
echo “script ended”
(2)位置参数
在linux当中参数的值是和它的位置有关的,比如下图中的$0就是表示./pp本身,$1表示的就是aaa
参数的位置不同代表的含义也不同,所以所有的参数都可以称之为命令参数,在vi编辑器中,书写函数之后需要在vi编辑器中进行函数的调用,这个时候为了区分不同位置的参数,姑且我将vi编辑器中的函数体内的参数称之为函数参数,将函数调用的参数称之为命令行参数。
如下两个代码块,第一个代码块表示的vi编辑器中的内容,第二个代码块代表的是命令行中的内容。
函数体中书写的$1参数实际上表示的就是函数调用的第一个参数“abc”,函数体中的$2参数实际上代表的就是函数调用的第二个参数“$1”。
而函数调用的第一个参数也就是函数参数$1实际上代表的是命令行中的第一个参数“a”,$$$
foo() {
echo "Function foo is executing"
echo $1
ecah $2
}
echo "script starting"
foo "abc" $1 $2
echo “script ended”
[stu@localhost ch02]$ ./function “a” “b”
六、流编译器
(1)sed工具
sed工具是一个“流编辑器”,适合执行重复的编辑,这种重复编辑如果由人工完成将话费大量的时间。流编辑器的使用是在命令行的窗口使用的,而并非是在vi编辑器的全屏幕编辑器中(这句话我能理解,但是对于读者来说可能会理解的不对,可以搜索相关资料学习)。在程序执行的过程当中可能没有打开全屏幕编辑器的条件或者不适合用vi的全屏幕编辑器的交互式的编辑方式。
在程序执行的时候,比如给出字符流的时候,可能需要在程序执行的过程中自动地去做,如下图所示:
① echo “xxx”是一个输出指令,输出xxx;
② | 是管道符的标志,将“xxx”交给sed;
③ -e表示两条命令同步执行,s代表用第2个斜杠后的字符串替换第1个斜杠后的字符串
sed的语法:sed [选择] ‘{命令}’ [文件名]
(2)awk的基本样式
第四章、linux下的c文件操作
一、标准c文件操作
fopen函数负责打开文件,常用格式是:文件指针=fopen(“文件名”,“文件权限”);
如下图,用变量c读入字符,用文件指针*in和*out指向对应的文件。具体实现的操作是:fgetc函数从in指向的文件中读入一个变量c到中,然后fputc将该变量中的字符写入out指向的文件中,一直执行到in读取到EOF(也就是文件尾部)的时候。
对于fgetc函数和fputc函数的解释:
在文件内部有一个位置指针,用来指向当前读写到的位置,也就是读写到第几个字节。在文件打开时,该指针总是指向文件的第一个字节。使用 fgetc() 函数后,该指针会向后移动一个字节,所以可以连续多次使用 fgetc() 读取多个字符。
注意:这个文件内部的位置指针与C语言中的指针不是一回事。位置指针仅仅是一个标志,表示文件读写到的位置,也就是读写到第几个字节,它不表示地址。文件每读写一次,位置指针就会移动一次,它不需要你在程序中定义和赋值,而是由系统自动设置,对用户是隐藏的。
二、系统调用
使用open函数,返回的东西是一个文件描述符(一个小的非负整数,最小的没有使用过的非负整数)
(1)open函数的几种表示形式
①int open(const char *pathname,int flags);
②int open(const char *pathname,int flags,mode_t);
(2)flags对应三个:
① O_RDONLY表示以只读的方式打开;
② O_WRONLY表示以只写的方式打开;
③ O_RDWR表示以可读可写的方式打开;
(3)mode_t使用的情况:
如下图,对于 O_WRONLY|O_CREAT 命令,如果文件不存在,那么就创建一个文件,mode_t参数表示的就是所创建的文件所有者的权限,S_IRUSR|S_WUSR表示赋予文件可读可写的权限。
注:
(1)Linux下任何一个进程都有三个默认打开的文件描述符:
① 0---标准输入(键盘)
② 1---标准输出(默认当前终端显示器)
③ 2---标准错误(默认当前终端显示器)
(2)如何判断错误:
返回值返回-1
read函数的表示:read(int fd,void *buf,size_t count);
①从文件描述符fd所指向的文件当中,读取字节长度为count的东西,放入到buf指针当中。
②如果count是0,read返回0;如果count比最大读取长度还要大的话,那么返回结果就不确定了。如果成功的话,则返回对应长度的字节内容,并且移动相应的位数。如果文件内容比要求的内容少的话,会返回小于要求字节的内容,这不是错误。
三、控制文件读写位置
(1)使用标准C语言函数fseek
fseek(FILE *stream,long offset,int whence)
① stream是一个文件指针
② whence是文件指针的基准(初始位置)
SEEK_SET:文件的开头
SEEK_CUR:文件指针当前所指向的位置
SEEK_END:文件的结尾
③ offset是文件指针的偏移量。
注:以下程序中的作用是:在文件hole.file中调用fwrite写入buf1中的内容,然后从文件头开始偏移40个字符后,调用fwrite在写入buf2的内容,在文件中的两个字符串之间造成了一个“空洞”,所造成“空洞”的地方实际上是 \0 字符。
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
① ptr-- 这是指向要被写入的元素数组的指针。
② size-- 这是要被写入的每个元素的大小,以字节为单位。
③ nmemb-- 这是元素的个数,每个元素的大小为 size 字节。
④ stream-- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。
fread
fclose
(2)使用系统调用lseek
lseek(int fd,off_t offset,int whence)
① fd是一个文件描述符
② whence是文件指针的基准(初始位置)
SEEK_SET:文件的开头
SEEK_CUR:文件指针当前所指向的位置
SEEK_END:文件的结尾
③ offset是文件指针的偏移量。
四、内存映射
void* mmap ( void *addr , size_t length , int prot , int flags , int fd , off_t offset);
① addr:映射区的开始地址。
设置为0时表示由系统内核决定映射区的起始地址(一般情况下都是设置成0)。
② length:映射区的长度。
长度单位是以字节为单位,不足一内存页按一内存页处理
③ prot:期望的内存保护标志。
不能与文件的打开模式冲突,可以通过or运算合理地组合在一起
PROT_EXEC //页内容可以被执行
PROT_READ //页内容可以被读取
PROT_WRITE //页可以被写入
PROT_NONE //页不可访问
④ flags:决定了映射的文件修改和改动是否能被其他进程看到
MAP_SHARED:对文件命令的修改别的进程可以看到
MAP_PRIBATE:对文件命令的修改别的进程看不到
⑤ fd:文件描述符,也就是被映射的文件
⑥ offset:映射从文件起始位置开始的偏移量
五、文件目录
操作目录结构的相关函数:
① opendir(目录名):如果该函数成功运行,用DIR *dp接收返回的访问目录的指针,如果失败将返回NULL。
② readdir(目录名):从返回的数据结构中读取一个表项,每读一次往下走一个;
③ closedir(目录名):关闭访问目录的指针。
习题:grep命令的代码实现
六、文件操作总结:
(1)文件指针:
使用标准c函数:fopen(),fread(),fwrite(),fclose(),fseek();
(2)文件描述符:
使用系统调用:open(),read(),write(),close(),lseek()。
(3)内存映射:
mmap()。
(4)文件目录:
opendir(),readdir(),closedir()。
第五章 进程
一、进程创建:fork命令
(1)fork命令说明
fork这个命令会创建一个子进程,将父进程当中所有的代码完整的复制一份给子进程。不同的地方在于,子进程有它自己的唯一的ID号。如果成功了,那么子进程的PID号会返回给父进程,0会返回给子进程。如果失败,则返回-1给父进程,此时不会有子进程的创建,并且会设置一个相对应的error number。
(2)实例讲解fork命令
① pid=fork(),创建了子进程的系统调用,正常有两个返回值;
② 对于switch对应的pid值,返回值0对应的是失败,返回值1对应的是子进程,返回值大于0对应的是父进程。fork执行成功,n这个变量在父进程和子进程中都存在,也就是在这两个分支当中,n实际上是不同的变量。
③ 对于后面的for循环,这一块代码在父子进程中各有一份,也就是说父进程会打印3行“This is the parent”,子进程会打印5行 “This is the child” 。
④ sleep可以强制性休眠一次,也就是结果会交替出现 “This is the parent” 和 “This is the child”。
⑤ 下方有强制休眠的话,结果显示会在最后一个 “This is the child” 前面显示美元符,这是因为父进程结束之后会显示父进程的父进程,也就是美元符。而如果没有强制休眠的话,就会在父进程结束之后显示。
⑥ 注意一点,父进程和子进程是并发执行的,所以谁先谁后其实并不一定,因此每一次执行的结果可能不一样。
二、wait调用
wait会把调用wait的这个进程的执行挂起,直到其中的一个子进程终止,同时返回子进程的状态,
waitpid可以指定等待某一个子进程。wait(&status)相当于waitpid(-1,&status,0);
WIFEXITED:如果子进程正常终止的话,返回true,并且返回子进程结束状态值。
pid_t waitpid ( pid_t pid , int * status , int options ) ;
(1) pid:参数 pid 为欲等待的子进程识别码
①pid<-1 等待进程组识别码为 pid 绝对值的任何子进程。
②pid=-1 等待任何子进程,相当于 wait( )。
③pid=0 等待进程组识别码与进程相同的任何子进程。
④pid>0 等待任何子进程识别码为 pid 的子进程。
(2) status:子进程的结束状态值会由参数 status 返回
①WIFEXITED(status):如果若为正常结束子进程返回的状态,则为真;对于这种情况可执行WEXITSTATUS(status),取子进程传给exit或_eixt的低8位。
②WEXITSTATUS(status)取得子进程 exit( )返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。
三、execl函数簇与system
(1)execl函数簇
利用新的进程映像替换老的进程映像,并且参数覆盖了下方的代码运行结果。如下图,运行之后不会在右边显示。因为新的进程映像把下方的printf语句覆盖掉了。
(2)system
system创建了一个进程,但是这个进程并没有替换当前的进程映像,而是哦创建了紫禁城,ls只是替换了子进程映像。父进程调用wait,等待子进程的进行,最后在父进程中打印 “ Done ”。
第六章 管道通信
一、无名管道pipe
(1)同进程使用管道通信
pipe无名管道的作用:是创建管道,是无方向的数据通路,可以被用来内部间的进程通信。返回两个文件描述符,pipefd[0]对应管道的读端,pipefd[1]对应管道的写端。数据从写端写入管道会被放到缓冲区保存起来,直到被读端读取。
① memset():对buffer缓冲区初始化,清零;
② pipe:pipe调用成功,返回两个文件描述符 file_pipes[0] 和 file_pipes[1] 分别关联管道的读端和写端。
(2)父子进程管道通信
管道在同进程中进行是无意义的,一般来说用于父子进程之间的通信。如上下图片所示程序,虽然执行结果一样,但是内涵不同。下方的代码使用了父子进程之间的管道通信。子进程继承了父进程的管道,父进程从管道的写端写入,子进程从管道的读端读出。
(3)不同进程管道通信
对下图代码的解析:
① sprintf将整型数file_pipes[0]转换成一个字符串,以适应execl调用中参数类型的要求。
② execl调用pipe4,pipe4将覆盖子进程空间,同时转换成字符串buffer的file_pipes[0],将成为pipe4的在命令行的第一个参数argv[1]。
③ 利用sscanf重新将字符串argv[1]转换成整形数file_descriptor,对应文件pipe3.c中管道的读端file_pipes[0]
(4)程序借助管道通信
关闭fd[0]和STD_OUTPUT,dup的使用会将最小的文件描述符与fd[1]匹配,然后关闭原本的fd[1],此时fd[1]对应的文件描述符应该是原本STD_OUTPUT所对应的。
使用pipe()创建管道,通过close()关闭标准描述符,dup()复制管道文件描述符。
二、有名管道(略)
mkfifo()
第七章 线程
一、线程的创建
int pthread_create
( pthread_t *tidp , const pthread_attr_t *attr , void *(*start_rtn)(void*) , void *arg ) ;
第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。
最后一个参数是运行函数的参数。
pthread_create的的返回值:若成功,返回0;若出错,返回出错编号。
下图中pthread_create的四个参数:
① &a thread:线程类型的变量,这个参数是指针,引用这个变量前面要加取地址符;
② NULL:线程属性取默认值;
③ thread_function:线程的入口函数
④ (void *)message:线程入口函数的参数

二、线程和进程的区别
线程中的资源一般来说是共享的,对县城中一个资源的修改,对于其他线程来说是可以看到的。
我的理解:其实可以类比于两个指针指向同一个地址,其中一个修改后,地址中的值就会改变。
对于进程来说,对资源的修改一般情况下其他进程是无法检测到的。

三、控制线程的执行顺序
(1)通过run now控制并发线程的执行



(2)通过信号量进行并发线程的执行
信号量初始化函数
int sem_init ( sem_t *sem , int pshared , unsigned int value ) ;
① sem :指向信号量对象
② pshared : 指明信号量的类型。不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享(一般情况下为0)。
③ value : 指定信号量值的大小
sem_init 成功时返回 0;错误时,返回 -1,并把error设置为合适的值。


四、总结
(1)线程创建
pthread create():
pthread join():
pthread exit():
(2)线程同步
sem init():
sem wait():
sem post():
sem destroy():
(3)线程属性(未介绍)
互斥体:
分离属性:
调度属性:
3875

被折叠的 条评论
为什么被折叠?



