linux的基础学习分享到这篇就结束了,本篇文章做最后的总结,也是对前面发布的linux学习的补足,并增加了linux的文件操作函数和目录操作函数部分,学海无涯,学无止境,linux的基础学习截至,但是博主的学习分享之路不会止境,接下来会分享什么,请看博主的CSDN目录:
此博主在CSDN发布的文章目录:【我的CSDN目录,作为博主在CSDN上发布的文章类型导读】
由于本篇文章篇幅有点长,请大家根据目录来选择阅读部分:
请查看:
VMware16安装,linux虚拟机安装,ubuntu20.04安装,VMware Tools工具安装【详细教程-图解】
Linux发行版的组成:linux内核 + 应用软件
linux应用软件一般包括:
命令行shell、GNU程序库和工具(GCC语言编辑器…)、一些图形桌面环境(KDE…)、一些办公软件(OpenOffice)、一些编译器(gcc、g++、python…)、一些文本编辑器到科学工具的应用软件(vi…)
linux版本有Redhat系列和Debian系列。
Redhat(RHEL)是商业公司维护的发行版本,包管理方式采用的是基于RPM包的YUM包管理方式。
Debian是社区组织维护的发行版本,包管理方式采用的是基于RPM包的YUM包管理方式。
RHEL(Redhat Enterprise Linux),Red Hat公司发布的面向企业用户的Linux操作系统,也是Redhat Advance Server收费版本。
CentOS(Community Enterprise Operating System)是免费的、开源的、可以重新分发的开源操作系统(RHEL的社区克隆版本,免费)。
FedoraCore,是一套从Red Hat Linux发展出来的免费Linux系统,由原来的Redhat桌面版本发展而来,免费版本,适用于桌面应用
Debian GNU/Linux(简称Debian)是目前世界最大的非商业性Linux发行版之一,是由世界范围1000多名计算机业余爱好者和专业人员在业余时间制做。(免费)
Ubuntu是以桌面应用为主的Linux操作系统,Ubuntu适用于笔记本电脑、桌面电脑和服务器,特别是为桌面用户提供尽善尽美的使用体验。Ubuntu几乎包含了所有常用的应用软件:文字处理、电子邮件、软件开发工具和Web服务等。用户下载、使用、分享未修改的原版Ubuntu系统,以及到社区获得技术支持,无需支付任何许可费用。(免费)
(ubuntu也是我介绍的重点,接下来介绍ubuntu的一些基础知识)
ubuntu的版本有Desktop(桌面版)和Server(服务器版),桌面版会至少有三年的技术支持,服务器版会至少有五年的技术支持,也是Ubuntu的LTS版(长期支持版)。
ubuntu分为主版本号和副版本号,主版本号代表年份,副版本号是月份,也就是说版本号的前两位数字表示发行时的年份,后两位表示发行的月份。
例如:ubuntu20.04,表示2020年4月份发布的版本,20.10就表示2020年10月份发布的版本。
单数年是短期支持版,双数年是长期支持版(LTS)。
4月版是该年度的稳定版,10月版是该年度的测试版,稳定版中发现的一些漏洞,或者一些改进的方案,就会放到10月版的测试版中测试。
推荐安装版本:
ubuntu18.04
ubuntu20.04
如何使U盘挂载到虚拟机上:将虚拟机全屏,再插入U盘,这样U盘就会挂载到你的虚拟机上。
mount:挂载U盘
用法:
sudo mount deviceName /mnt
#deviceName 为你的U盘名字
例如:sudo mount /dev/sdb1 /mnt
如何在没有挂载上U盘的时候知道你的U盘名字,也就是/dev/sdb1
使用命令:sudo fdisk -l
该命令会帮你获取到U盘的名字(是第二个[设备][启动]的列项)
umount:卸载U盘
#U盘的卸载—你不能在你要卸载的目录中。
用法:
umount /你的U盘路径
例如:umount media/itcast/UpName
如果你手动的将你的U盘挂载到了非/mnt目录中,它会覆盖掉该目录中的内容,只是临时的覆盖,将U盘卸载后,原来的目录依然存在。
为什么使用sudo fdisk -l命令获取到的设备名字是sdb1?
硬盘的种类有三种:
sd --> SCSI Device
hd --> Hard Disk 硬盘
fd --> Floppy Disk 软盘
有一块盘就是sda,两块就是sdb,这样命名的
在一块硬盘里最多只能有四块主分区,主分区是被占用的,从sda1-4,然后就是扩展分区,也就是逻辑分区,第一块逻辑分区是从sda5开始的。
/bin目录:存放经常使用的命令
/boot目录:存放的是开机启动命令,不能乱删
/dev目录:存放的是设备文件,将所有的设备抽象成一个文件来保存
/etc目录:存放安装的文件需要的配置文件
/home目录:存放所有用户的目录
/lib目录:存放的是linux需要用到的动态库(windows的动态库是dll)
/lost+found目录:存放的是文件碎片,电脑非法关机后,一些未保存的文件就会存在这里,用于恢复
/media目录:linux系统会自动识别一些设备,例如U盘,光驱等,当识别后,就会挂载到该目录下
/mnt目录:如果没有自动识别设备,需要手动挂载,就挂载在该目录下
/opt目录:第三方软件目录
/proc目录:对内存的映射
/root目录:超级权限者的用户主目录
/sbin目录:系统管理员使用的系统管理程序
/tmp目录:存放一些临时文件
/usr目录:应用程序目录
/usr/bin目录:系统用户使用的应用程序
/usr/sbin目录:超级用户使用的比较高级的管理程序和系统守护程序
/usr/src目录:内核源代码默认的放置目录
/var目录:经常被修改的目录放在该目录下,包括各种日志文件
#目录前的提示字符串
itcast@ubuntu:~$
itcast:表示当前登录用户
@:at 在
ubuntu:主机名
~:用户的家目录
$:当前用户为普通用户
#:超级用户
cd /bin #转到bin目录
cd . #表示当前目录
cd .. #表示当前上级目录
cd - #表示在两个目录之间切换,
cd ~ #表示当前用户的家目录
ls #显示当目录中的文件,不包括隐藏文件
ls / #查看根目录下的子文件
ls -a #查看当前目录下所有的文件,包括隐藏文件
ls -l #查看文件的详细详细信息,不包括隐藏文件
ls -la #列出所有文件的详细信息,包括隐藏文件
ls -l test.txt #显示test.txt文件的详细信息
#文件详细信息 ls -al
d rwx rwx r-x 3 ubuntu ubuntu 4096 3月 4 21:33 testfile
第1个字符表示文件类型:[-]普通文件、d目录、l链接符号、b块设备、c字符设备、[s]socket文件、[p]管道
接下来9个字符,三三一组,分别表示:
第2-第4个字符(rwx): 表示当前文件所有者的权限,即当前文件属于哪一个人
第5-第7个字符(rwx): 表示同组用户的权限,文件属于哪一个组,这个组里的人
第8-第10个字符(r-x): 表示其他人的权限,就是不属于这个组的人就是其他人
r --> read(读)
w --> write(写)
x --> zhixing(执行)
- --> 表示无权限
【第11个字符(3):该文件硬链接数】
接下来的每一组:
ubuntu: 该文件或目录的所有者
ubuntu: 该文件或目录所属的组
4096: 占用的存储空间(目录占用的空间就是4096kb)
3月 4 21:33: 文件最后创建或修改的时间
testfile: 文件名字
#文件或目录的颜色一般情况
白色 – 普通文件
蓝色 – 目录
绿色 – 可执行文件
红色 – 压缩文件
青色 – 链接文件
黄色 – 设备文件
block 块(例如硬盘…)
char 字符(键盘…)
fifo 管道
灰色 – 其他文件
#创建目录
mkdir fileName #创建一个名称为fileName的文件夹
mkdir -p dir1/dir2/dir3 #创建复合文件夹,路径dir1/dir2/dir3
#创建文件
touch test #创建一个名为test的文件,如果文件不存在,创建文件,如果文件存在,修改文件的创建时间
#/删除文件夹
rmdir fileName #删除fileName文件夹,只能删除一个空文件夹
rm -r dir1/dir2/dir3 #删除非空文件夹,注意,该命令删除后就没了,很难找回来,r表示递归的意思
rm -r fileName/* #删除掉fileName里的内容,并不删除fileName目录
rm -ri dir1/dir2/dir3 #删除非空文件夹,会一个文件夹一个文件夹的提示是否需要删除
#删除文件
rm test #删除一个名称为test的文件
rm *.txt #删除当前目录下的txt文件
#拷贝(复制)文件
cp test1 test2 #将test1文件的内容拷贝到test2文件里,如果test2文件不存在,会自动创建一个test2文件,如果test2文件存在,就覆盖掉test2文件里的内容
#拷贝(复制)目录
cp -r fileName newName #将fileName文件夹中的文件拷贝newName文件夹中,如果newName文件不存在,则创建该文件,然后在拷贝,如果存在,则将fileName文件夹放到newName文件夹中
#只将testfile1文件中的内容拷贝到testfile2中
cp testfile1/* testfile2
cat test #查看当前文件的内容,不适合长文件
more test #查看文件内容,回车键每次显示一行内容,空格键翻页,只能往后翻,q键退出,ctrl+c也可以退出
less test #查看文件内容,回车键每次显示一行内容,空格键翻页,ctrl+p往前看,ctrl+n往后看,ctrl+b向前翻页,ctrl+f向后翻页
head test #查看文件内容,默认显示前十行
head -50 test #查看文件内容,显示前50行
tail test #查看文件内容,默认显示后十行
tail -50 test #查看文件内容,显示后50行
#给文件改名字
mv fileName newName #给文件改名字,如果newName存在,则将fileName放入到其中,如果不存在,则将fileName改名为newName
mv fileName ../ #将fileName移动到上级目录
#创建软链接(相当于创建快捷方式)
ln -s test.c test.soft #test.c为要创建快捷方式的原文件名字,test.soft(后缀加不加都行)为要创建的快捷方式的名字,test.soft文件大小为test.c字符个数(即为6)
ln -s ~/filetext/test.c test.soft #使用绝对路径创建软链接,这样将软链接移到别处也一样可以用
例如:
lrwxrwxrwx 1 wang wang 22 3月 5 22:12 test -> /home/wang/Wangc/test1
给目录创建软链接的方式和给文件创建软链接的方式是一样的。
#创建硬链接(也就是给文件备份)
只能给文件创建硬链接
linux文件系统的存储单元是块
ln test.c test.hard #创建硬链接,不需要指定路径,不管移到哪里,都可以用
whoami #查看当前登录用户
#修改文件权限
chmod命令
chmod [who] [+|-|=] [mode] 文件名
操作对象[who]:
u:用户(user)
g:同组用户(group)
o:其他用户(other)
a:所用用户(all)【默认】
操作符[±=]:
+:添加权限
-:取消权限
=:赋予给定权限并取消其他权限
权限[mode]:
r:读
w:写
x:执行
例如:chmod u + wx file.txt
数字表示的含义
0:没有权限(-)
1:执行权限(x)
2:写权限(w)
4:读权限(r)
操作符【±=】
+:添加权限
-:取消权限
=:赋予给定权限并取消其他权限 (默认为=)
例:chmod 777 file.txt
第一个7表示:文件所有者
第二个7表示:文件所有组
第三个7表示:其他人
减权限:chmod -001 file.txt 或者 chmod 000 file.txt(所有人都没有权限)
#修改文件的所有者和所属组
chown #将指定文件的拥有者改为指定的用户或组
#修改所有者
chown + 文件所属用户 + 文件或目录名
sudo chown nobody text.txt
#修改所有者和所属组
chown + 文件所属用户:文件所属组 + 文件或目录名
sudo chown nobody:nogroup text.txt
#只修改所属组
chgrp #改变文件或目录的所属群组
chgrp + 用户组 + 文件或目录名
sudo chgrp nogroup text.txt
注意:作为一个目录必须有执行权限,没有执行权限,是进不去该目录的
find #查找命令,
1、按文件名查询:-name
find + 路径 + -name + 文件名
例如:find /home -name a.txt
使用通配符:
*:通配 0 - n个字符
?:通配1个字符
例如:find /home -name a*
2、按文件大小查询:-size
find + 路径 + -size + 范围
范围
大于:+表示 – +100k
小于:-表示 – -100k
等于: 不需要添加符号 – 100k
注意:大小:M 必须大写 k 必须小写
例子:
等于100k的文件: find ~/ -size 100k
大于100k的文件: find ~/ -size +100k
大于50k, 小于100k的文件: find ~/ -size +50k -size -100k
3、按文件类型查询:-type
find + 路径 + -type + 类型
类型
①普通文件类型用 f 表示而不是 -
②d:目录
③l:符号链接
④b:块设备文件
⑤c:字符设备文件
⑥s:socket文件,网络套接字
⑦p:管道
例如:find /home -type d
grep #按文件内容查找
参数:-r
grep -r + “查找的关键字” + 路径
例如:grep -r "main void" /home/itcast
wc #获取文本文件的信息(行 单词个数(以空格为准) 字节数 文件名称)
参数
wc -c: 只显示字节数
wc -l: 只显示行数
wc -w:只显示字数
例如:
wc test.txt #获取test.txt文本文件的信息(行 单词个数(以空格为准) 字节数 文件名称)
od #查看二进制文件信息
参数
od tc:以ASCII字符形式显示
od td:以有符号十进制数显示
od tf:以浮点数显示
od to:以八进制数显示
od tu:以无符号十进制数显示
od tx:以十六进制数显示
例如:
od -tc testbin #获取二进制文件的信息,以ASCLL码形式展现
du #查看某个目录的大小
du -h #查看当前目录的大小,以我们能看懂的方式(h human)
例如:du -h fileName
df #查看磁盘的使用情况
df -h #以我们能看懂的方式展现
例如:df -h
which #查看指定命令所在的路径
which指令会在PATH变量指定的路径中,搜索某个系统命令的位置,并且返回第一个搜索结果。
which cd #显示找不到?因为cd是bash 内建的命令
安装:sudo apt-get install tree -- 在线下载安装
移除:sudo apt-get remove tree
更新:sudo apt-get update -- 更新软件列表
清理所有软件安装包: sudo apt-get clean
实际清理的是: /var/cache/apt/archives 目录下的 .deb 文件
使用该工具需要安装:sudo apt-get install aptitude
安装:sudo aptitude install tree
重新安装:sudo aptitude reinstall tree
更新:sudo apt-get update
移除:sudo aptitude remove tree
显示状态:sudo aptitude show tree #查看是否安装
sudo dpkg -i xxx.deb #安装xxx.deb
sudo dpkg -r xxx #删除软件
①解压缩源代码包
②进入到安装目录:cd dir
③检测文件是否缺失,创建Makefile,检测编译环境: ./configure
④编译源码,生成库和可执行程序:make
⑤把库和可执行程序,安装到系统目录下:sudo make install
⑥删除和卸载软件:sudo make distclean
⑦上述安装步骤并不是绝对的,应该先查看附带的 README 文件
sudo apt-get update #访问源列表里的每个网址,并将软件列表保存在本地电脑
sudo apt-get upgrade #会把本地已安装的软件,与软件列表里对应软件进行对比,如果发现已安装的软件版本太低,就会提示你更新
apt list --upgradable #查看当前列表哪些软件可以更新
//搜索安装包
sudo apt search xxx
sudo apt search python
gzip:压缩文件
用法:
gzip *.txt
注意事项:
压缩过程中不保留源文件
不能对目录进行压缩
不能对多个文件进行打包压缩
gunzip :解压缩
用法:
gunzip *.gz
bzip2:压缩文件
用法:
bzip2 *.txt
注意事项
通过使用参数 -k(keep) 保留源文件
不能对目录进行压缩
不能对多个文件进行打包压缩
与gzip的区别:
bzip2 -k *.zip #使用该命令压缩可以保留源文件
bunzip2:解压缩
用法:
bunzip2 *.bz2
tar:不使用z/j参数,该命令只打包不压缩
tar的内部依然是调用gzip或者bzip2来压缩,tar本身只进行一个打包的功能。
z -> 用 gzip 来压缩/解压缩文件
j -> 用 bzip2 来压缩/解压缩文件(z/j命令互斥)
c -> create,创建新的压缩文件。如果用户想备份一个目录或是一些文件,就要选择这个选项。
x -> 从压缩文件中释放文件(c/x命令互斥)
v -> 详细报告tar处理的文件信息
f -> 指定压缩文件的名字
tar + 参数(zcvf) + 压缩包名字.tar.gz + 原材料(要打包压缩的文件或目录)
tar + 参数(jcvf) + 压缩包名字.tar.bz2 + 原材料(要打包压缩的文件或目录)
用法:
tar jcvf testfile.tar.bz2 testfile/ *.txt #使用bz2 格式压缩,将testfile文件夹压缩,且将testfile文件夹的同级路径中的txt文件一起打包压缩,不仅可以压缩目录,还可以一起压缩文件
tar + 参数(zxvf) + 已有的压缩包(test.tar.gz)
tar + 参数(jxvf) + 已有的压缩包(test.tar.bz2)
指定解压目录:添加参数 -C(大写) tar zxvf test.tar.gz -C + 解压目录(./mytest)
用法:
tar jxvf testfile.tar.bz2 -C test/ #将testfile压缩包中的内容解压到test文件中
使用前需要安装 rar 工具:sudo apt-get install rar
rar <命令> -<选项1> ….-<选项N> <操作文档> <文件…> <@文件列表…> <解压路径>
命令
a -> 添加文件到操作文档
x -> 带路径解压文档中内容到当前目录
选项
r -> 递归子目录(可写可不写)
rar a -r + 压缩文件名(newdir) + 压缩的目录(./mydir)
打包的生成的新文件不需要指定后缀
用法:
rar a all *.txt #压缩当前文件夹里的txt文件
rar a frar file #将file文件夹压缩为frar.zip
rar x newdir.rar
解压到指定目录
rar x all.rar + 目录(/home/itcast/test)
用法:
rar x all.rar ./ #将all.rar解压到当前路径
对目录打包需要添加参数: -r
zip -r + 打包之后的文件名(dir.zip) + (打包的目录)dir
[压缩完后显示的提示信息,0%表示完全压缩,100%表示没有压缩过]
例如:
zip txt *.txt #将当前目录下的txt文件压缩为txt.zip
zip -r z.rar testfile #将testfile文件夹压缩为z.zip
unzip dir.zip
解压到指定目录:
使用参数 -d 来指定目录
unzip dir.zip -d /home/itcast/test
用法:
unzip dir.zip -d /home/itcast/test #将dir.zip解压到/home/itcast/test目录中
who:查看当前在线用户的情况
登录的用户名
使用的设备终端(pts)
登录到系统的时间
tty 设备
tty1 - tty6 表示文字界面
ctrl + alt + [F1-F6]
tty7 图形界面 切换:ctrl + alt + F7
ps:查看整个系统内部所运行的进程状况
a:(all)当前系统所有用户的进程
u:查看进程所有者及其他一些信息
x:显示没有控制终端的进程 -- 不能与用户进行交互的进程【输入、输出】
用法:
ps a #当前系统所有用户的进程
ps au #查看进程所有者及其他一些信息(PID:进程ID,%CPU:内存的使用率,TTY:终端)
ps aux #显示没有控制终端的进程 -- 不能与用户进行交互的进程【输入、输出】
ps aux | grep xxx:在进程中查找名字中带有xxx的进程
使用管道过滤
1、什么是管道(|)
将指令1的输出作为指令2的输入,指令2处理完毕,将信息输出到屏幕
用法:
ps aux | grep bash #查找进程中带有bash的进程
注意:
①grep查询是需要占用一个进程的,所有结果 > 2 才能说明查询结果存在
②如果结果有一条,表示没有查询的进程
③查询结果中PID表示进程ID
kill:用来终止指定的进程(terminate a process)的运行
kill -l #查看信号编号
kill -SIGKILL 【PID-进程ID号】 #向当前进程发送了9号信号(SIGKILL),杀死当前进程
也可以写成:kill -9【PID-进程ID号】
查看进程ID命令:ps aux
例如:
kill -SIGKILL 89899 #杀死89899进程
env:查看当前进程环境变量
环境变量说明:
1、当前系统下用户的配置路径信息
2、格式为键值对:key=value:value (多个值之间用 :分隔)
3、PATH:该环境变量中记录着shell命令解析器去查找命令的目录位置,从前往后的顺序查找
top:查看进程,相当于windows下的任务管理器,文字版,不能翻页
ctrl+c退出
ifconfig:获取网络接口配置信息,还可以修改这些配置。
使用该命令需要安装:sudo apt install net-tools
例如:
ping:测试与目标主机的连通性
命令格式:ping [参数] [主机名或IP地址]
-c 数目:在发送指定数目的包后停止。
-i 秒数:设定间隔几秒送一个网络封包给一台机器,预设值是一秒送一次
ping www.baidu.com #ping百度的服务器,按ctrl+c结束
ping www.baidu.com -c 4 #ping百度的服务器,4次自动结束
ping www.baidu.com -i 2 #ping百度的服务器,2s回馈一次
nslookup:查看服务器域名对应的IP地址
一般访问网站都是使用域名,如:www.baidu.com,使用该命令就可查看百度所有服务器的IP地址
用法:
nslookup www.baidu.com #查看百度的ip
作用:文件的上传和下载,(远程下载数据等)
sudo apt-get install vsftpd -- 客户端服务器都会被安装
服务安装完毕之后,ftp服务会随开机自动启动
服务器进行配置,配置给客户端使用,修改配置文件的时候,别人格式怎么写就怎么写,不要乱写
修改配置文件:/etc/vsftpd.conf
文件中:
write_enable=YES #是否拥有写权限
anon_root=/home/itcast/ftp #匿名用户ftp根目录
anonymous_enable=YES #是否允许使用匿名用户
anon_upload_enable=YES #是否允许匿名用户上传权限
anon_mkdir_write_enable=YES #是否允许匿名用户创建目录
gedit /etc/vsftpd.conf #使用gedit文本编辑器打开该文件
配置后需要重启ftp,重启命令:
sudo service vsftpd restart
配置完成之后,必须重启服务器新的配置才能够生效
启动命令
service vsftpd start
重启命令:
sudo service vsftpd restart
– 通用,与版本无关
注意:是把当前电脑当成服务器,对方可以远程连接服务器,进入你的电脑上传或者下载文件。
连接服务器:ftp + 服务器ip(192.168.1.100)
Name: 服务器用户名(server的)
Password:服务器登录密码(server的)
用户可以访问服务器的任意目录
往该目录上传文件
从该目录下载文件
注意:
①需要将登陆密码告诉登陆用户–非常不安全
②登陆进来的用户可以访问ftp服务器的任意目录–非常不安全
在登录的时候不需要密码.
连接服务器:ftp + 服务器Ip(192.168.1.100)
Name:(输入)anonymous (匿名用户)
Password: (不填,直接回车)
可以限制用户登录上来的位置,用户只能在限制的范围进行操作,也就是不允许随意切换目录。
1、需要在服务器电脑上修改配置文件
(即指定匿名用户的ftp根目录,可修改目录的权限,让客户端不能在服务器中乱操作)
方法1:
/etc/vsftpd.conf
配置文件中添加:anon_root=/home/itcast/ftp
#/home/itcast/ftp为匿名用户默认访问位置
方法2:
使用默认位置:/srv/ftp
可搜索/etc/passwd 文件中的ftp,里边给出了默认路径 /srv/ftp
方法3:
在指定好的ftp目录下创建一个供匿名用户上传下载的目录
sudo mkdir /srv/ftp/anonPersion
修改权限方法1:
sudo chown ftp:nogroup /srv/ftp/annoPersion
#把目录的所用者指定为ftp用户
#设置组为nogroup,即不属于任何组
修改权限方法2:
chmod 777 anonPersion
注意:不能上传下载目录,如有需求需要打包
上传文件命令:put xxx
在哪个目录下登录ftp服务器,就只能上传哪个目录中的文件
下载文件命令:get xxx
在哪个目录下登录ftp服务器,文件就下载到哪个位置
注意:在哪个目录下登录服务器,就可以上传该目录下的文件到服务器,上传其他文件夹中的数据,则需要在其他文件夹中重新登录到服务器。
查看当前上传位置: pwd
退出登录:
quit
exit
bye
sudo chkconfig vsftpd on #设置ftp服务器开机自动运行
sudo chkconfig vsftpd off #关闭ftp服务器开机自动运行
service vsftpd stop #停止ftp服务器
ps -ef | grep ftp #查看ftp进程是否开启
lftp:一个ftp客户端工具, 可以上传和下载目录
可以显示服务器ip和所在目录
命令:sudo apt-get install lftp
(1)匿名
1. lftp 服务器ip (回车)
2. login (用户名)
(2)实名
1. lftp [email protected] 回车
2. 输入服务器密码
put:上传文件
mput:上传多个文件
例如:mput 1.c 2.c
get 下载文件
mget 下载多个文件
mirror 下载整个目录及其子目录
例如:mirror testfile
mirror –R 上传整个目录及其子目录
例如:mirror -R testfile
lpwd:查看登录用户所在的目录
lcd :切换登录用户的目录位置,
例如:lcd /home/itcast/testfile
#切换到/home/itcast/testfile目录中
nfs(net file system):网络文件系统,它允许网络中的计算机之间通过TCP/IP网络共享资源。
安装:sudo apt-get install nfs-kernel-server
如:mkdir /home/xxx/xxx(/home/itcast/itcast)
命令:sudo vi /etc/exports
写入需要共享目录的路径:
如:/home/itcast/itcast *(ro,sync,no_root_squash)
/home/itcast/itcast :表示共享路径
*:代表一个IP地址段,如:192.168.10.* (有的版本这样写有问题,目录无法共享出去)
ro -> 只读权限
rw -> 读写权限
sync -> 资料同步写入到内存与硬盘当中
async -> 资料会先暂存于内存当中,而非直接写入硬盘
no_root_squash -> 登入NFS主机,使用该共享目录时相当于该目录的拥有者,如果是root的话,那么对于这个共享的目录来说,他就具有root的权 限,这个数『极不安全』,不建议使用
root_squash -> 登入NFS主机,使用该共享目录时相当于该目录的拥有者。但是如果是以root身份使用这个共享目录的时候,那么这个使用者(root)的权限将被压缩成为匿名使用者,即通常他的UID与GID都会变成nobody那个身份
all_squash -> 不论登入NFS的使用者身份为何,他的身份都会被压缩成为匿名使用者,通常也就是nobody
sudo service nfs-kernel-server restart #重启nfc服务
首先挂载目录:
mount + IP:共享目录名 挂载目录
例如:
sudo mount 192.168.32.75:/home/itcast/itcast/ /mnt #将/home/itcast/itcast/挂载到/mnt中
cd 到本机的/mnt
目录中就可以使用cp命令得到目录中的所有文件。
ssh(Secure Shell):服务器管理员通过ssh远程登录外地主机,进行维护(远程登录主机,就跟本人在本地登录主机是一样的)
命令:sudo atp-get install openssh-server
查看SSH是否安装
命令:sudo aptitude show openssh-server
ssh 用户名@IP
输入密码
确认连接的时候一定要写yes/no(不能写y或者n)
例如:
ssh [email protected]
命令:logout
scp (super copy):能够跨越主机拷贝,只需要获取远程服务器上的某个目录,就能直接拷贝了,不用搭建服务器
使用该命令的前提条件
目标主机已经成功安装openssh-server
命令:sudo apt-get install openssh-server
scp -r 目标用户名@目标主机IP地址:/目标文件的绝对路径 /保存到本机的绝对(相对)路径
在后续会提示输入“yes”此时,只能输“yes”而不能简单输入“Y”
例如:
scp -r [email protected]:/home/itcast/QQ_dir/ ./mytest/360
注意:拷贝目录需要加参数 -r
who:查看当前在线用户的情况
登录的用户名 使用的设备终端(pts) 登录到系统的时间
whoami #查看当前登录用户
命令格式:
sudo adduser + 用户名(luffy)
-s 指定新用户登陆时shell类型
-g 指定所属组,该组必须已经存在
-d 用户家目录
-m 用户家目录不存在时,自动创建该目录
sudo adduser username #添加一个名为username的用户,会提示你输入一些该用户的信息,如果输入用大写字母,会报错
sudo useradd -s /bin/bash -g ITcast -d /home/ITcast -m ITcast #带大写字母创建用户
sudo groupadd ITcast #创建ITcast组
格式:id 用户名 #查看用户名的所属用户组
用法:id testuser #查看testuser用户的所属组
格式:
cat /etc/group | grep 用户名 #根据筛选出来的内容查看用户名的所属用户组
用法:
cat /etc/group | grep testuser #根据筛选出来的内容,查看testuser用户的所属组
格式:
groups 用户名 #查看用户名的所属用户组
chown:将指定文件的拥有者改为指定的用户或组
格式:
chown + 文件所属用户 + 文件或目录名
用法:
sudo chown testuser text.txt #修改text.txt文件的所有者为testuser
#修改所有者和所属组
chown + 文件所属用户:文件所属组 + 文件或目录名
sudo chown nobody:nogroup text.txt
#只修改所属组
chgrp #改变文件或目录的所属群组
chgrp + 用户组 + 文件或目录名
sudo chgrp nogroup text.txt
注意:作为一个目录必须有执行权限,没有执行权限,是进不去该目录的
命令格式:
sudo deluser + 用户名(luffy)
sudo userdel -r itcast
选项 -r 的作用是把用户的主目录一起删除
用法:
sudo deluser ITcast #删掉ITcast用户,但是不删除他的家目录
sudo userdel -r ITcast #删除ITcast用户,连同家目录一起删掉
命令格式:
su + 用户名(sanji)
root用户
sudo su
用法:
su ITcast #切换到ITcast用户
命令格式:
sudo passwd + 用户名 #修改用户名的登录密码
用法:
sudo passwd ITcast #修改ITcast的密码
passwd #修改当前用户的密码
sudo passwd #修改root用户密码,或sudo passwd root
在etc下有一个passwd文件,文件中每一行就对应一个用户。(etc/passwd)
exit #退出当前用户
使用以下命令的时候必须加管理员权限,也就是在命令前+sudo
sudo poweroff #在一定时间后关机
sudo reboot #在一定时间后重启
-t 秒数 : 设定在切换至不同的runlevel之前, 警告和删除二讯号之间的延迟时间(秒).
-k : 仅送出警告讯息文字, 但不是真的要 shutdown.
-r : shutdown 之後重新开机.
-h : shutdown 之後关机.
-n : 不经过 init , 由 shutdown 指令本身来做关机动作.(不建议你用)
-f : 重新开机时, 跳过 fsck 指令, 不检查档案系统.
-F : 重新开机时, 强迫做 fsck 检查.
-c : 将已经正在 shutdown 的动作取消.
shutdown -r now #立刻重新开机
shutdown -h now #立刻关机
shutdown -k now 'Hey! Go away! now....' #发出警告讯息, 但没有真的关机
shutdown -t3 -r now #立刻重新开机, 但在警告和删除processes 之间, 延迟3秒钟.
shutdown -h 10:42 'Hey! Go away!' #10:42 分关机
shutdown -r 10 'Hey! Go away!' #10 分钟後关机
shutdown -c #将刚才下的 shutdown 指令取消,必须切换至其它tty, 登入之後, 才能下此一指令.
shutdown now #切换至单人操作模式(不加任何选项时)
①vi和vim都是文本编辑程序
②vim是从vi发展过来的一款文本编辑器
③没有菜单,只有命令,且命令繁多
命令:sudo apt-get install vim
打开文件之后, 默认进入命令模式。
命令模式下在键盘上按键:
h: ← 左移
l: → 右移
j: ↓ 下移
k: ↑ 上移
gg: 光标移动文件开头
G: 光标移动到文件末尾
0: 光标移动到行首
$: 光标移动到行尾
123G:跳转到第123行
注意:并不是真的删除,实际上是剪切
命令模式下在键盘上按键:
x: 删除光标后一个字符,相当于 Del
X: 删除光标前一个字符,相当于 Backspace
dw: 删除光标开始位置的字,包含光标所在字符
光标必须移动到删除单词的首字符上
d0: 删除光标前本行所有内容,不包含光标所在字符
D(d$): 删除光标后本行所有内容,包含光标所在字符
dd: 删除光标所在行
n dd 删除指定的行数
命令模式下在键盘上按键:
u: 一步一步撤销
Ctr-r: 反撤销
命令模式下在键盘上按键:
yy: 复制当前行,n yy 复制 n 行
p: 在光标所在位置向下新开辟一行,粘贴
P: 从光标所在行, 开始粘贴
命令模式下在键盘上按键:
v:切换到可视模式
操作:
配合 h、j、k、l 使用,按字移动,
h: ← 左移
l: → 右移
j: ↓ 下移
k: ↑ 上移
按下y键复制选中内容
按下d键删除选中内容
按下p键粘贴,会在光标所在处后直接粘贴
按下esc键进入命令模式
命令模式下在键盘上按键:
r: 替换当前字符,只能替换单个字符
命令模式下在键盘上按键:
>>: 文本行右移,向右缩进
<<: 文本行左移,向左缩进
①光标移动到函数上,Shift-k 光标移动到函数上,会从linux提供的man文档的开头开始查找,直至查找到第一个该函数为止。
②3Shift-k,查看第三章的 ManPage
命令模式下保存退出: ZZ
需要输入一些命令, 切换到编辑模式。
命令模式切换到输入模式:
i #在插入光标前一个字符
I #插入行首
a #插入光标后一个字符
A #插入行未
o #向下新开一行,插入行首
O #向上新开一行,插入行首
s #删除光标所在的字符
S #删除当前行
esc #切换到命令模式
在末行模式下可以输入一些命令。
命令模式下在键盘上按键:
: #命令模式切换到末行模式
按两次esc #末行模式切换到命令模式
键盘输入:
:123 -> 跳转到第123行
键盘输入:
:/hello #从光标所在位置向后查找 hello,以高亮形式显示
n: 切换下一个
N:切换上一个
:?hello #从光标所在位置向前查找 hello
n: 切换上一个
N:切换下一个
在要查询的单词上使用 # 进行查找
1、替换一行
:s/abc/123 #将当前行中的第一个abc替换为123
:s/abc/123/g #将当前行中的abc全部替换为123
2、替换全部
:%s/abc/123 #将所有行中的第一个abc替换为123
:%s/abc/123/g #将所有行中的abc全部替换为123
3、替换指定行
:10,30s/abc/123/g #将10-30行中的abc全部替换为123
末行模式里输入!,后面跟命令::! +命令
键盘输入:
:q #退出
:q! #退出不保存
:w #保存
:wq #保存退出
:x #保存退出
末行模式
命令:sp 将屏幕分为两部分 --> 水平
命令:vsp 将屏幕分为两部分 --> 垂直
命令:sp(vsp) + 文件名 水平或垂直拆分窗口显示两个不同的文件
操作
命令:wqall 保存并退出所有屏幕
命令:wq 保存并退出光标所在的屏幕
CTrl+ww 切换两个屏幕
永久显示行号方法:
输入命令:
vim ~/.vimrc #在用户主目录创建一个.vimrc文件
该文件中添加:set number
保存退出重新打开vim即可。
使用前需要安装:
sudo apt install gcc #安装gcc编译器,编译C程序
sudo apt install g++ #安装g++编译器,编译C++程序
gcc编译的四个阶段分为:
1.预处理 -E(使用参数)
2.编译 -S(使用参数)
3.汇编 -c(使用参数)
4.链接 没有参数
例如:
gcc -E hello.c -o hello.i #预处理阶段,生成预处理文件hello.i
gcc -S hello.i -o hello.s #编译阶段,生成编译文件hello.s
gcc -c hello.s -o hello.o #汇编阶段,生成二进制文件hello.o
gcc hello.o -o hello #链接阶段,生成可执行文件
若是想跳过四个阶段,直接生成可执行文件,执行如下命令:
gcc hello.c -o hello
gcc一些参数说明:
-o: 指定生成的文件的名字
-D: 在编译的时候定义宏(控制log的输出)
-I: 指定头文件的路径(大写的i)
-g: gdb调试的时候需要添加该参数
-O: 编译优化, 3个等级 -O(1-3)
-Wall: 编译期间输出警告信息
-v / --version #查看版本号
例如:
gcc -v #查看gcc编译器版本号
g++ -v #查看g++编译版本号
-o #给可执行文件改名字,不指定生成可执行文件的名字,默认生成a.out
例如:
gcc main.c -o main #生成的可执行文件叫main
-I +目录 #指定头文件的位置(大写的i)
例如:
gcc main.c -I ./testinclude -o main #编译mian.c,指定头文件存放位置在testinclude文件夹中
-D +宏 #在代码中用到的宏,可以不用在代码中定义,在编译的时候定义
例如:
gcc main.c -o main -D DEBUG #在代码中用到了DEBUG这个宏,但是在代码中没有定义,在编译的时候定义了,这种写法可以用来控制log是否打印等…
-On #编译优化等级n=0∼3,对代码进行优化,比如代码有冗余:int a=10;int b=a;优化成了b=10;
-O0 - 没有优化
-O1 - 缺省值
-O3 - 优化级别最高
例如:
gcc main.c -o main -O3 #进行代码优化编译
-Wall #输出警告信息
例如:
gcc main.c -o main -Wall #输出代码的一些警告,比如变量未使用
-c #编译的第三阶段
生成动态库静态库文件的时候就需要加-c参数,
gcc -c hello.s -o hello.o #生成二进制文件hello.o
-E #编译的第一阶段
gcc -E hello.c -o hello.i #预处理阶段,生成预处理文件hello.i
-g #gdb调试的时候必须加此参数
例如:
gcc main.c -o main -g #生成调试信息,+g参数,生成的可执行文件要比没加g的时候大,因为里面多了调试信息
主要是编译c++文件,使用方法同gcc
linux的静态库是以.a结尾的,而windows的静态库是以.lib结尾的,本次来介绍的是linux的静态库。
1、优点
①寻址方便,加载速度快
②库被打包到可执行程序中,直接发布可执行程序即可使用
2、缺点
①静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
②如果静态函数库改变了,那么你的程序必须重新编译。
3、使用场合
①在核心程序上使用,保证速度,可忽视空间
②主流应用于80、90年代,现在很少用
做项目的时候,一般很少将源代码给商家,都是将自己的源码打包成库给商家。
静态库命名方式:
libsort.a #lib开头,sort静态库名,.a结尾
1、gcc/g++命令生成 *.o文件
使用gcc/g++编译器命令:
gcc a.c b.c c.c -c #生成二进制文件a.o、b.o、c.o
接下来就要用这些.o文件打包成静态库了。
2、ar打包,得到静态库 libmytest.a
ar rcs libmytest.a a.o b.o c.o #使用ar工具将需要的.o打包,若是该目录下有不需要的.o文件,就不要将其打包进来,
若是没有不要的.o文件,也可写成命令:
ar rcs libmytest.a *.o
(就是一个打包.o文件的过程)
ar 工具不包含在gcc中
参数说明:
r --> 将文件插入静态库中
c --> 创建静态库,不管库是否存在
s --> 写入一个目标文件索引到库中,或者更新一个存在的目标文件索引。
查看库中的符号(.o文件、函数、全局变量等): nm libmytest.a
注意:自己写程序调用别人的静态库时,可执行文件中只打包使用到的别人的静态库中的.o文件,没有使用到的.o是不被打包到自己的程序里的,即生成的二进制文件是与位置有关的,调用的静态库里的.o会被直接打包进自己写的程序可执行文件中(而动态库不会,动态库只是做了一个位置的记录)。
命令格式:
gcc + 源文件 + -L 静态库路径 + -l 静态库名 + -I头文件目录 + -o 可执行文件名
-L --> 指定库所在的路径
-l --> 指定库的名字(小写的l)
去掉前缀 lib
去掉后缀 .a
只留下中间部分
-I --> 头文件目录位置(大写的i)
例如:
gcc main.c -L ./ -l mytest -I ./ -o app #使用静态库编译程序
命令格式:
gcc + 源文件 + -I头文件 -o 可执行文件名称 +路径/libxxx.a
例如:
gcc main.c -I ./ -o app ./mylib/libxxx.a #使用静态库编译程序
生成的静态库需要跟对应的头文件同时发布
头文件中存放的是函数接口(函数声明)
linux的动态库是以.so结尾的,而windows的动态库是以.dll结尾的,现在来介绍的是linux的动态库(也有的人叫共享库)。
1、机制
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
2、优点
①节省内存(共享)
②易于更新(动态链接)
停止运行程序
使用新库覆盖旧库(保证新旧库名称一致,接口一致) “接口”
重新启动程序。
3、缺点
延时绑定,速度略慢
4、使用场合
对速度要求不是很强烈的地方都应使用动态库
5、注意事项
动态库是否加载到内存,取决于程序是否运行。
命令格式:
libmytest.so #lib开头,动态库名,.so 结尾
linux动态库制作和使用,会遇到一些问题,不过这些都不难,博主都给出了简易的解决方案,只需要按照博主的步骤,按部就班就可以解决问题。
命令使用:
gcc -fPIC a.c b.c c.c -c
参数 -fPIC 表示生成与位置无关代码,用的相对地址(生成的.o文件)
执行完毕后生成一系列的 .o 文件
调用动态库时,并不会将调用到对应动态库中.o文件打包到自己写的程序可执行文件中,而是对动态库的位置做了记录,是程序起来了再去加载动态库(静态库则是不一样,会将.o打包到自己的可执行程序文件中)。
使用gcc/g++编译器命令:
gcc -shared -o libmytest.so a.o b.o c.o
参数:-shared 制作动态库
-o:生成动态库文件的名称
或:gcc -shared -o libmytest.so *.o
#打包当前路径下的所有.o文件为动态库,注意,若是当前路径下有无关的.o,也会被打包进去,所以使用*.o的时候最好将当前路径下的无关.o移出去
使用gcc/g++编译器命令:
gcc main.c -L./ -lmytest -I./ -o app
说明:
-L --> 指定库所在的路径,
-l --> 去掉前缀 lib,去掉后缀 .so,只留下中间部分
-I --> 头文件目录位置
在使用动态库以后,生成自己的可执行文件myapp会运行失败,报错:动态库找不到。
./myapp --> 运行失败
这时候我们可以去查看myapp依赖的共享库,查看依赖的共享库命令:ldd myapp
问题原因:发现.so找不到,是因为没有给动态链接器(ld-linux.so.2)指定好动态库 libmytest.so 的路径
/ld-linux-x86-64.so.2:动态链接器,按照这种规则去调用我们的动态库
(1)临时解决(设置)
使用命令:export LD_LIBRARY_PATH=库路径
,将当前目录加入环境变量,但是终端退出了就无效了。(代码测试)
LD_LIBRARY_PATH介绍:
1、作用
①指定查找共享库(动态链接库)时除了默认路径之外的其他路径
②该路径在默认路径之前查找
2、设置方法
用export命令来设置值
例如:export LD_LIBRARY_PATH=./mylib
#设置mylib文件夹路径为我们动态库所在的路径
echo $LD_LIBRARY_PATH #打印该环境变量
(2)永久解决(设置)
将export LD_LIBRARY_PATH=./mylib
写入家目录下.bashrc文件中,这样就可以永久设置了。
修改了bashrc文件后,需要将终端关掉再次打开,该文件才能生效。
(3) 永久设置(正规写法)
步骤:
/etc/ld.so.conf
/home/myproject/mylib
sudo ldconfig -v
linux下C/C++程序调试,需要使用GDB工具,若是没有安装该工具,则输入命令:sudo apt-get install gdb
终端输入命令:gdb -v #查看gdb版本
GDB(GNU Debugger)是gcc的调试工具,其功能强大。
GDB主要帮忙你完成下面四个方面的功能:
1.启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
2.可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
3.当程序被停住时,可以检查此时你的程序中所发生的事。
4.动态的改变你程序的执行环境。
一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,我们必须要把调试信息加到可执行文件中。使用编译器(gcc/g++)的 -g 参数可以做到这一点。如:
gcc -g hello.c -o hello
g++ -g hello.cpp -o hello
如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。当你用-g把调试信息加入之后,并成功编译目标代码以后,让我们来看看如何用gdb来调试他。
命令:
gdb program    #program 也就是你的执行文件,一般在当前目录下。
set args #可指定运行时参数。(如:set args 10 20 30 40 50 )
show args #命令可以查看设置好的运行参数。
run #运行程序,跑到断点出停止,可简写成r
start #运行程序,开始只执行一步
cd #相当于shell的cd命令。
pwd #显示当前的所在目录。
GDB会报告程序停在了哪个文件的第几行上。
可以用list命令来打印程序的源代码,list默认打印10行。
list可以简写成(l)
l #默认打印main函数所在的文件前10行,输入一次l以后,当你想继续查看剩下的代码,直接按回车就可以了
l linenum #在当前源文件中以行号linenum为中心打印行。
l function #显示函数名为function的函数的源程序。
l testfile.c:20 #从testfile.c文件的第20行开始显示
l testfile.c:testfunc #显示testfile.c文件的testfunc函数代码
l - #显示当前行前面的源程序。
#一般是打印当前行的上5行和下5行,如果显示函数是是上2行下8行,默认是10行,当然,你也可以定制显示的范围,使用下面命令可以设置一次显示源程序的行数。
set listsize count #设置一次显示源代码的行数(listsize)。(除非列表参数显式指定其他数字)
show listsize #查看当前listsize的设置。
break #设置断点,可以简写为b
b 10 #设置断点,在源程序第10行
b func #设置断点,在func函数入口处
在进入指定函数时停住:
C++中可以使用class::function或function(type,type)格式来指定函数名。如果有名称空间,可以使用namespace::class::function或者function(type,type)格式来指定函数名。
例如:
break filename:linenum -- 在源文件filename的linenum行处停住
break filename:function -- 在源文件filename的function函数的入口处停住
break class::function或function(type,type) -- 在类class的function函数的入口处停住
break namespace::class::function -- 在名称空间为namespace的类class的function函数的入口处停住
info b #或者简写成i b
一般来说,为断点设置一个条件,我们使用if关键词,后面跟其断点条件。
例如,设置一个条件断点:
b test.c:8 if intValue==5 #在test.c第8行设置一个断点,只有在intValue=5时生效
b 15 if i==5 #在当前文件第15行设置断点,只有i等于5时生效
注意:在使用run命令的时候,设置的条件断点只能在循环内部,否则程序不会停止
delete [range…] #删除指定的断点,如果不指定断点号,则表示删除所有的断点。
range 表示断点号的范围(如:3-7)。其简写命令为d。
例如:
d #删除所有断点
d 1 #删除1断点号对应的断点,格式:d +断点好号
d 2-4 #删除第2-4的断点
比删除更好的一种方法是disable停止点,disable了的停止点,GDB不会删除,当你还需要时,enable即可,就好像回收站一样。
disable [range...] #disable所指定的停止点,如果什么都不指定,表示disable所有的停止点。简写命令是dis.
enable [range...] #enable所指定的停止点,如果什么都不指定,表示enable所有的停止点。简写命令是ena.
disable和enable 用法和delete一样。
run #运行程序,可简写为r
next #(可简写为n)单步跟踪,函数调用当作一条简单语句执行
step #(可简写为s)单步跟踪,函数调进入被调用函数体内
finish #退出进入的函数,若是你的函数里有断点,是不能退出的
until #(可简写为u)在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体,即跳出当前(for)循环
continue #(可简写为c)继续运行程序
p j #(print)查看j变量的值
ptype arr #查看arr变量的类型
display j #在循环中,每循环一次,就会把变量j的值打印出来,前提是j存在
i display #查看你追踪变量的编号
undisplay 1 #取消编号为1的变量打印
set var i=10 #在运行时,设置变量i=10,就是设置变量的值
quit #退出gdb调试
使用前请安装make,安装命令:sudo apt install make
①要么第一个字母大写,剩余字母小写,例如:Makefile
②要么全部字母小写:makefile
①项目代码编译管理
②节省编译项目的时间
③一次编写终身受益
格式:
目标:依赖
(tab)命令
解释:
目标 --> 要生成的目标文件
依赖 --> 生成目标文件需要的一些文件
命令 --> 借助依赖文件生成目标文件的手段
tab --> 缩进,在第二行开始
Makefile会把规则中的第一个目标作为终极目标
app:依赖 #指定生成的最终目标为app
写该用例前请自己先创建add.c、sub.c、main.c源文件,否则执行makefile的时候会出错。
创建一个makefile文件,在其中添加如下内容:
mycalc:add.c sub.c main.c -o mycalc
gcc add.c sub.c main.c -o mycalc
#该代码功能:(在makefile文件中用#进行注释)
#执行gcc add.c sub.c mul.c div.c -o mycalc
命令,生成mycalc可执行文件
①若想生成目标,检查规则中的依赖条件是否存在,
②如果不存在,寻找是否有规则用来生成该依赖文件
③检查规则中的目标是否需要更新,必须检查它的所有依赖,
④依赖中有任意一个被更新,则目标必须更新
⑤依赖文件比目标文件时间晚,则需要更新
make怎么知道哪个文件被更新了?
make根据文件修改的时间来进行对比的,源文件生成的时间<.o生成的时间<最终目标生成的时间,这样就知道哪个文件被修改了,可看用例二。
写该用例前请自己先创建main.c、add.c、sub.c、mul.c源文件,否则执行makefile的时候会出错。
创建一个makefile文件,在其中添加如下内容:
app:main.o add.o sub.o mul.o
gcc main.o add.o sub.o mul.o -o app
main.o:main.c
gcc -c main.c
add.o:add.c
gcc -c add.c
mul.o:mul.c
gcc -c mul.c
sub.o:sub.c
gcc -c sub.c
解释说明:
①make先检查main.o add.o sub.o mul.o是否存在,若是不存在,则会向下寻找是否有用来生成该依赖条件的文件;
②第4行到第14行都是对第一行的依赖条件的生成,make就会去找这些行依赖;
③使用该种方法,第一次编译后,若是main.c或者其他某单个文件被修改(make会对比文件修改的时间),只会编译对应的单个文件,就不会全部文件都被编译一次,这样更节省时间。
make的执行命令如下:
make #makefile文件的路径下,终端执行命令:
make +objname #执行makefile文件中的objname目标
使用方法请看用例三
写该用例前请自己先创建add.c、sub.c、mul.c、div.c源文件,否则执行makefile的时候会出错。
创建一个makefile文件,在其中添加如下内容:
app:main.o add.o sub.o mul.o
gcc main.o add.o sub.o mul.o -o app
main.o:main.c
gcc -c main.c
add.o:add.c
gcc -c add.c
mul.o:mul.c
gcc -c mul.c
sub.o:sub.c
gcc -c sub.c
clean:
rm main.o add.o sub.o mul.o
这个时候,终端执行命令:make
是编译.c文件
终端执行命令: make clean
就会删除掉main.o add.o sub.o mul.o这四个文件。
问题1:
如果当前目录下有同名clean文件会怎么样?
答:报错:clean已是最新,即不执行clean对应的命令。
解决方案:
添加伪目标声明代码:.PHONY:clean
makefile文件中的代码更改如下:
app:main.o add.o sub.o mul.o
gcc main.o add.o sub.o mul.o -o app
main.o:main.c
gcc -c main.c
add.o:add.c
gcc -c add.c
mul.o:mul.c
gcc -c mul.c
sub.o:sub.c
gcc -c sub.c
.PHONY:clean #伪目标声明
clean:
rm main.o add.o sub.o mul.o -f #-f是强制执行这个命令,无论有没有这些.o文件
这样就不会出现上述问题了。
问题2:
在执行makefile的时候,当你执行完一条命令出错后,就不会在执行剩下的命令了,这时候,我们在命令的前面加入特殊-,表示此条命令出错,make也会继续执行后续的命令。如:“-rm a.o b.o”
变量定义及赋值:obj = a.o b.o c.o
变量取值:foo = $(obj)
由 Makefile 维护的一些变量,通常格式都是大写
例如:
CC =cc #系统变量CC默认为cc,也就是gcc
有些有默认值,有些没有
CPPFLAGS : 预处理器需要的选项 如:-I
CFLAGS:编译的时候使用的参数 –Wall –g -c
LDFLAGS :链接库使用的选项 –L -l
用户可以修改这些变量的默认值
CC = gcc
(请看用例四。)
1、自动变量规则:
$@ #规则中的目标
$< #规则中的第一个依赖条件
$^ #规则中的所有依赖条件
都是在规则中的命令中使用
2、模式规则
在规则的目标定义中使用 %
在规则的依赖条件中使用 %
3、示例:
%.o:%.c
$(CC) –c $< -o $@
$< #表示依次取出依赖条件
$@ #表示依次取出目标值
% #表示一个或者多个
$^ #规则中的所有依赖
(请看用例四。)
现将用例三中makefile的代码做如下修改:
obj=main.o add.o sub.o mul.o
target=app
CC = gcc
$(target):$(obj)
$(CC) $(obj) -o $(target)
%.o:%.c
$(CC) -c $< -o $@
.PHONY:clean #伪目标声明
clean:
rm main.o add.o sub.o mul.o -f
(这样一写是不是就看着简洁很多了~~)
执行的功能效果和用例三是一样的。
makefile中所有的函数必须都有返回值,在这里介绍两个常用的函数。
查找指定目录下指定类型的文件,该函数有一个参数
用法:src = $(wildcard ./src/*.c)
#找到./src 目录下所有后缀为.c的文件,赋给变量src,其中./src/*.c就是该函数的参数了
匹配替换,从src中找到所有.c 结尾的文件,并将其替换为.o
用法:
#把src变量中所有后缀为.c的文件替换成.o
obj = $(patsubst %.c ,%.o ,$(src))
#指定.o 文件存放的路径 ./obj/%.o
ob = $(patsubst %.c, ./obj/%.o, $(src))
注意:在写目标的时候,也需要加上路径
./obj/%.o:%.c
xxx
当然,makefile的函数肯定不止这些,这里只是介绍两个常用的。
现将用例四中makefile的代码做如下修改:
target=app
src=$(wildcard ./*.c)
obj=$(patsubst %.c, %.o, $(src))
CC = gcc
$(target):$(obj)
$(CC) $(obj) -o $(target) -I./1
%.o:%.c
$(CC) -c $< -o $@
.PHONY:clean #伪目标声明
clean:
rm main.o add.o sub.o mul.o -f
(执行的功能效果和用例四是一样的。)
ctrl+shift+c #终端复制
ctrl+shift+v #终端粘贴
ctrl+c #终止程序
ctrl+p 或者向上↑方向键 #历史命令向上遍历
ctrl+n 或者向下↓方向键 #历史命令向下遍历
#光标移动
ctrl+b #向前移动
ctrl+f #向后移动
ctrl+a #直接跳到行首
ctrl+e #直接跳到行尾
ctrl+h #删除光标前面的一个字符
ctrl+d #删除光标后面的一个字符
ctrl+u #删除光标前面的全部字符
Shift + PageUp #上翻页
Shift + PageDown #下翻页
clear
Ctrl + l
Ctrl + Alt + T (Ubuntu)
Ctrl + Shift +T (添加新标签页)
命令: man man
帮助手册共九个章节:
1、可执行程序或shell命令
2、系统调用(内核提供的函数)
3、库调用(程序库中提供的函数)
4、特殊文件(通常位于/dev)
5、文件格式和规范(如:/etc/passwd)
6、游戏
7、杂项
8、系统管理命令
9、内核例程
命令使用:
man 2 open #查看man第二章中的open函数
查看
alias
例如:alias ls #查看命令是否被封装
如下图:
我们执行的ls命令实际是执行的ls --color=auto 命令
设置
alias pag=‘ps aux | grep’
若是要长久有效,需要去设置配置文件:.bashrc
echo:在显示器上显示数据
普通数据:echo 字符串
显示环境变量:echo $PATH
显示上一次程序退出值:echo $?
$ : 从变量中取值
?:最近一次程序退出时的返回值
data #查看时间
history #查看历史命令
pwd #查看当前所在的全路径
#tab键提示命令
如果记不全命令了,就按一次tab键,按一次没有反应,就按两次
#新开一个终端 "test"为名字
gnome-terminal -t "test" -x bash -c "python test.py;exec bash"
#test为终端的名字,python test.py;exec bash为执行的命令
sleep 8 #终端停止8s
先来看C语言的文件函数:
(每一个文件只有一个文件指针,当你打开一个文件后,操作了文件指针,没有关闭,下次打开的时候,文件指针就不再指向文件开头,而是指向你上次操作文件指针的位置)
这里重点解释一下I/O缓冲区:
C文件库函数每次读字符的时候,将读取到的字符数据都会放到一个I/O缓冲区中,当这个缓冲区(8kb)满了,才向硬盘(文件中)写入数据,因为这样效率会快些(内存是纳秒级的、硬盘是毫秒级的)。
linux每一个运行的程序(进程),操作系统都会为其分配一个0~4G的地址空间(虚拟地址空间)下,系统提供了4G的虚拟地址空间并不是进程起起来后就少了4G的内存,而少的是你实际用了多少内存。
通过命令:
file +可执行程序名称 #可以查看文件类型
在内核区有一个PCB进程块,在PCB进程块中有一个文件描述符表,一个进程,用户最多能打开1021个文件,前三个默认被打开(标准输入、标准输出、标准错误),
cpu 为什么要使用虚拟地址空间与物理地址空间映射?解决了什么样的问题?
1.方便编译器和操作系统安排程序的地址分布。
程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。
2.方便进程之间隔离
不同进程使用的虚拟地址彼此隔离。一个进程中的代码无法更改正在由另一进程使用的物理内存。
3.方便OS使用你那可怜的内存。
程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,
内存管理器会将物理内存页(通常大小为 4 KB)保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动。
系统调用函数都必须考虑返回值。
unix有自己的数据类型,比C更早出现。
函数作用: 打开一个文件
头文件:
#include
#include
#include
为什么会有三个,因为flags参数的值不同,会在另外头文件中找。
函数原型:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
函数参数:
pathname:文件的相对或绝对路径
flags:打开方式
必选项(互斥)
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 可读可写打开
可选项
O_APPEND 表示追加。如果文件已有内容,这次打开文件所写的数据附加到文件的末尾而不覆盖原来的内容。
O_CREAT 若此文件不存在则创建它。
使用此选项时需要提供第三个参数mode,表示该文件的访问权限。
文件权限由open的mode参数和当前进程的umask掩码共同决定
O_EXCL 如果同时指定了O_CREAT,并且文件已存在,则出错返回。
O_TRUNC 如果文件已存在,则将其长度截断(Truncate)为0字节,即删除原有文件的内容。
O_NONBLOCK 设置文件为非阻塞状态
mode: 文件权限,是八进制数,当然,也可以传十进制数(十进制数可以从八进制权限转换),例如:0777
返回值:
①返回-1表示打开文件失败;
②否则返回新的文件描述符。
常见错误:
1. 打开文件不存在
2. 以写方式打开只读文件(打开文件没有对应权限)
3. 以只写方式打开目录
umask #查看本地掩码
umask 022 #修改掩码为022
文件权限: 本地有一个掩码
文件的实际权限:
本地掩码(取反) & 给定的权限 = 实际的文件权限
例如:
本地掩码为0002,进行权限运算:
即0777 & (~0002) = 0775
打开文件-创建新的文件:
判断文件是否存在:
删除文件的内容,也就是将文件截断:
头文件:
#include
errno是全局变量,任何标准C库函数都能对其进行修改(Linux系统函数更可以),当我们执行函数出错时,就会给该全局变量赋一个值,就代表对应的出错信息。
错误宏定义位置:
第 1 - 34 个错误定义:
/usr/include/asm-generic/errno-base.h
第 35 - 133 个错误定义:
/usr/include/asm-generic/errno.h
说明:
①是记录系统的最后一次错误代码,代码是一个int型的值
②每个errno值对应着以字符串表示的错误类型
③当调用"某些"函数出错时,该函数会重新设置 errno 的值
我们可以通过perror函数打印当前出错的信息。
头文件:
#include
函数原型:
void perror(const char *s)
函数说明:
①用来将上一个函数发生错误的原因输出到标准设备(stderr)
②参数 s 所指的字符串会先打印出,后面再加上错误原因字符串
③此错误原因依照全局变量errno 的值来决定要输出的字符串。
头文件:
#include
函数原型:
int close(int fd);
参数:
fd:文件描述符
返回值:
0 --> 正常关闭
-1 --> 关闭出现错误
函数作用:
从打开的设备或文件中读取数据。
头文件:
#include
函数原型:
ssize_t read(int fd, void *buf, size_t count);
参数说明:
fd:文件描述符
buf:数据缓冲区
count:请求读取的字节数
返回值:
-1 --> 错误
>0 --> 读出的字节数
=0 --> 文件读取完毕
函数作用:
向打开的设备或文件中写数据。
头文件:
#include
函数原型:
ssize_t write(int fd, const void *buf, size_t count);
参数说明:
fd:文件描述符
buf:需要输出的缓冲区
count:最大输出字节数
返回值:
-1 --> 失败
>=0 --> 写入文件的字节数
#include
#include
#include
#include
#include
#include
int main()
{
/*实现功能,将test.c中的内容读取出来,并写入到新建的文件hello.c中*/
//打开test.c文件
int fp1 = open("test.c",O_RDWR);//需要自己创建test.c文件
if(fp1 == -1)
{
perror("ERROR open:");
exit(1);
}
//创建文件hello.c
//0777表示权限,公式:实际的文件权限 = 本地掩码(取反) & 给定的权限
//本地掩码查看命令:umask
int fp2 = open("hello.c",O_RDWR | O_CREAT | O_EXCL, 0777);
if(fp2 == -1)
{
perror("ERROR open:");
exit(1);
}
int ira = 1;
char buf[1024] = {0};
while(ira > 0)
{
ira = read(fp1,buf,sizeof(buf));//读取test.c文件的数据
int iwr = write(fp2,buf,ira);//将读出来的数据写入到hello.c中
printf("本次写入字节:%d\n",iwr);//打印写入字节
}
//关闭文件
close(fp1);
close(fp2);
return 0;
}
函数作用:
修改文件偏移量(读写位置)
头文件:
#include
#include
函数原型:
off_t lseek(int fd, off_t offset, int whence)
参数说明:
int fd --> 文件描述符
off_t offset --> 偏移量
int whence --> 偏移位置
SEEK_SET - 从文件头向后偏移
SEEK_CUR - 从当前位置向后偏移
SEEK_END - 从文件尾部向后偏移
返回值:
较文件起始位置向后的偏移量
允许超过文件结尾设置偏移量,文件会因此被拓展。
失败返回 -1
应用
拓展文件空间
获取文件长度
lseek(fd, 0, SEEK_END); 返回值即为文件长度
#include
#include
#include
#include
#include
#include
int main()
{
int fp1 = open("test",O_RDWR);//需要自己创建test文件
if(fp1 == -1)
{
perror("ERROR open:");
exit(1);
}
//获取aa文件大小
int ret = lseek(fp1,0,SEEK_END);
printf("file length = %d\n",ret);
//实现aa文件的文件拓展,从文件末尾开始拓展
ret = lseek(fp1,2000,SEEK_END);//从文件末尾开始扩展
printf("return file length is %d\n",ret);
//实现文件拓展需要向文件任意写一点东西(此步骤必须存在)
write(fp1,"",1);
close(fp1);
/*
文件拓展的作用:在下载文件的时候,通常会有个临时文件,这个文件也叫空洞文件,这是在你开始下载文件的时候就会存在,它的大小是跟你需要下载的文件大小是一样的,是为了检测你是否有这么多内存来下载本文件,这个临时文件的大小就是用文件拓展来做的,里面的内容就是一堆乱码。
*/
return 0;
}
函数作用:
将字符串按对应进制转换为整型数字。
头文件:
#include
函数原型:
long int strtol(const char *nptr, char **endptr, int base);
long long int strtoll(const char *nptr, char **endptr, int base);
函数参数:
nptr:需要转换的字符串
endptr:当nptr中存在非数字字符时,该指针会指向第一个不属于数字的字符地址
base:需要转换的进制
返回值:
返回的是整型数。(10进制)
例子:
#include
#include
int main()
{
char ch[64] = "1235as5",*ch1;
int ret = strtol(ch,&ch1,10);//按10进制转换,ch1会指向a
printf("%d %s\n",ret,ch1);
//输出结果:1235 as5
return 0;
}
在mkdir函数例子中有应用。
stat不仅是一个函数,还是一个命令;
stat +filename #显示filename文件的一些属性
函数作用:
获取文件属性(从inode上获取)
头文件:
#include
#include
#include
函数原型:
int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
参数说明:
pathname:文件路径
statbuf:文件属性结构体
fd:文件描述符
文件属性结构体:
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
blksize_t st_blksize; //块大小(文件系统的I/O 缓冲区大小)
blkcnt_t st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
返回值:
成功:0
失败:-1
特性:
stat能够穿透(跟踪)符号链接,例如读软链接文件,则会是软链接映射到的文件的大小;
lstat不穿透,如果是读链接文件,则就是链接文件的大小。
#include
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("a.out filename\n");
exit(1);
}
struct stat buf_st;
int ret = stat(argv[1], &buf_st);//获取文件属性
if(ret == -1)
{
perror("stat");
exit(1);
}
printf("file size: %d\n", (int)buf_st.st_size);//打印文件大小
ret = lstat(argv[1], &buf_st);//获取文件属性
if(ret == -1)
{
perror("lstat");
exit(1);
}
printf("file size: %d\n", (int)buf_st.st_size);//打印文件大小
/*
区别:
stat能够穿透(跟踪)符号链接,例如读软链接文件,则会是软链接映射到的文件的大小;
lstat不穿透,如果是读链接文件,则就是链接文件的大小。
*/
return 0;
}
函数作用:
测试指定文件是否拥有某种权限
头文件:
#include
函数原型:
int access(const char *pathname, int mode);
函数参数:
pathname --> 文件名
mode --> 权限类别
R_OK 是否有读权限
W_OK 是否有写权限
X_OK 是否有执行权限
F_OK 测试一个文件是否存在
返回值:
0 --> 所有欲查核的权限都通过了检查
-1 --> 有权限被禁止
#include
#include
#include
int main(int argc, char* argv[])
{
int ret = access(argv[1], W_OK);//检查文件是否有写权限
if(ret == -1)
{
perror("access");
exit(1);
}
printf("you can write this file!\n");
return 0;
}
函数作用:
改变文件的权限
头文件:
#include
函数原型:
int chmod( const char *filename, int pmode );
int fchmod(int fd, mode_t mode);
函数参数:
filename:文件名
fd:文件描述符
pmode:权限
必须是一个8进制数
返回值:
0 --> 改变成功
-1 --> 失败
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("a.out filename\n");
exit(1);
}
int ret = chmod(argv[1], 0755);//修改文件权限为0755
if(ret == -1)
{
perror("chmod");
exit(1);
}
return 0;
}
函数作用:
改变文件的所有者
头文件:
#include
函数原型:
int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char *pathname, uid_t owner, gid_t group);
函数参数:
pathname:文件路径
owner:所有者id
group:所属组id
fd:文件描述符
在 /etc/paswd 文件中可查看所有者id和所属组id,格式说明:
登录名:可选的加密后的密码:所有者 ID:所属组 ID:用户名和注释字段:用户主目录:可选的用户命令解释器
返回值:
0 --> 成功
-1 --> 失败
#include
#include
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("a.out filename!\n");
exit(1);
}
// user->ftp group->ftp
int ret = chown(argv[1], 116, 125);//修改文件所有者和所属组
if(ret == -1)
{
perror("chown");
exit(1);
}
return 0;
}
函数作用:
将参数path 指定的文件大小改为参数length 指定的大小。如果原来的文件大小比参数length大,则超过的部分会被删去。专门做文件扩展的函数
头文件:
#include
#include
函数原型:
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
函数参数:
path:文件路径
fd:文件描述符
length:指定的文件大小,多出来的内存以空洞形式占有
返回值:
0 --> 执行成功
-1 --> 执行失败
#include
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc < 3)
{
printf("a.out filename 111\n");
exit(1);
}
long int len = strtol(argv[2], NULL, 10); //传入的字符串换成整型数字
int aa = truncate(argv[1], len);//将文件的大小改为len
if(aa == -1)
{
perror("truncate");
exit(1);
}
return 0;
}
函数作用:
创建一个硬链接
头文件:
#include
函数原型:
int link(const char *oldpath, const char *newpath);
函数参数:
oldpath:需要创建硬链接的文件名字
newpath:创建后硬链接文件的名字
返回值:
返回0成功
返回-1失败
17.15.1.例8
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc < 3)
{
printf("a.out oldpath newpath\n");
exit(0);
}
int ret = link(argv[1], argv[2]);//给argv[1]文件创建一个名为argv[2]的硬链接
if(ret == -1)
{
perror("link");
exit(1);
}
return 0;
}
函数作用:
创建一个软连接
头文件:
#include
函数原型:
int symlink(const char *target, const char *linkpath);
函数参数:
target:需要创建软链接的文件名字
linkpath:创建后软链接文件的名字
返回值:
返回0成功
返回-1失败
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc < 3)
{
printf("a.out oldpath newpath\n");
exit(1);
}
int ret = symlink(argv[1], argv[2]);//给argv[1]文件创建一个名为argv[2]软链接
if(ret == -1)
{
perror("symlink");
exit(1);
}
return 0;
}
函数作用:
读取软链接的文件路径名(不是读软链接映射文件中的内容)
头文件:
#include
函数原型:
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
函数参数:
pathname:软链接文件名字
buf:对应链接到的文件路径和名字
bufsiz:buf的大小
返回值:
返回-1失败
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("a.out softlink\n");
exit(1);
}
char buf[512];
int ret = readlink(argv[1], buf, sizeof(buf));//读取argv[1]软链接文件的路径名,放在buf中
if(ret == -1)
{
perror("readlink");
exit(1);
}
buf[ret] = 0;
printf("buf = %s\n", buf);
return 0;
}
函数作用:
删除一个文件的目录项并减少它的链接数,若成功则返回0,否则返回-1,错误原因存于errno。
如果想通过调用这个函数来成功删除文件,你就必须拥有这个文件的所属目录的写和执行权限。
头文件:
#include
函数原型:
int unlink(const char *pathname);
函数参数:
pathname:对应链接的文件名字
返回值:
成功返回0,
失败返回-1。
使用
1. 如果是符号链接,删除符号链接
2. 如果是硬链接,硬链接数减1,当减为0时,释放数据块和inode
3. 如果文件硬链接数为0,但有进程已打开该文件,并持有文件描述符,则等该进程关闭该文件时,kernel(内核)才真正去删除该文件,利用该特性创建临时文件,先open或creat创建一个文件,马上unlink此文件
#include
#include
#include
#include
#include
#include
//删除临时文件场景
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("a.out filename\n");
exit(1);
}
int fd = open(argv[1], O_CREAT | O_RDWR, 0755);//打开文件
if(fd == -1)
{
perror("open");
exit(1);
}
int ret = unlink(argv[1]);//立马删除文件
if(ret == -1)
{
perror("truncate");
exit(1);
}
char buf[128];
write(fd, "hello", 5);//将hello写入该文件
lseek(fd, 0, SEEK_SET);//文件指针指向开头
int len = read(fd, buf, sizeof(buf));//读取文件内容
write(STDOUT_FILENO, buf, len);//STDOUT_FILENO是标准输出的文件描述符为1,将读取到的内容写到屏幕上
close(fd);//文件关闭后删除该文件
return 0;
}
函数作用:
文件重命名
头文件:
#include
函数原型:
int rename(const char *oldpath, const char *newpath);
函数参数:
oldpath:旧文件名字
newpath:新文件名字
返回值:
返回0成功,
返回-1失败。
#include
#include
int main(int argc, char* argv[])
{
if(argc < 3)
{
printf("a.out oldName newName\n");
exit(1);
}
int ret = rename(argv[1], argv[2]);//将argv[1]文件改名为argv[2]
if(ret == -1)
{
perror("rename");
exit(1);
}
return 0;
}
函数作用:
修改当前进程的路径
头文件:
#include
函数原型:
int chdir(const char *path);
函数参数:
path:需要改变的工作路径(是当前进程的)
返回值:
返回0成功
返回-1失败
//例子请看例13
函数作用:
获取当前进程工作目录
头文件:
#include
函数原型:
char *getcwd(char *buf, size_t size);
函数参数:
buf:当前进程所在的工作路径,获取到的路径放在buf中
size:buf的大小
返回值:
返回NULL失败
否则返回和buf一样的值
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("a.out dir\n");
exit(1);
}
int ret = chdir(argv[1]);//修改当前进程的路径为argv[1]
if(ret == -1)
{
perror("chdir");
exit(1);
}
//在修改后的进程工作目录创建文件
int fd = open("chdir.txt", O_CREAT | O_RDWR, 0777);
if(fd == -1)
{
perror("open");
exit(1);
}
close(fd);
char buf[128];
getcwd(buf, sizeof(buf));//获取当前进程工作目录,放到buf中
printf("current dir: %s\n", buf);
return 0;
}
函数作用:
创建目录
注意:创建的目录需要有执行权限,否则无法进入目录
头文件:
#include
函数原型:
int mkdir(const char *pathname, mode_t mode);
函数参数:
pathname:需要创建的目录名字
mode:给定该目录的权限
返回值:
返回0成功;
返回-1失败
#include
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc < 3)
{
printf("a.out newDir mode\n");
exit(1);
}
//例如:
//传入:qq 700
//表示创建一个名为qq的目录,所有者权限为可读可写可执行,所属组和其他人没有权限
int mode = strtol(argv[2], NULL, 8);//将argv[2]字符串按照八进制转换为10进制
int ret = mkdir(argv[1], mode);//创建目录,mode可以为10进制数,也可以为8进制数,但都会按照文件的权限来进行转换的
/*
文件权限:
0:没有权限(-)
1:执行权限(x)
2:写权限(w)
4:读权限(r)
*/
if(ret == -1)
{
perror("mkdir");
exit(1);
}
return 0;
}
函数作用:
删除一个空目录
头文件:
#include
函数原型:
int rmdir(const char *pathname);
函数参数:
pathname:需要删除的目录名字
返回值:
返回0成功;
返回-1失败。
函数作用:
打开一个目录
头文件:
#include
#include
函数原型:
DIR *opendir(const char *name);
函数参数:
name:目录名字
返回值:
DIR结构指针,该结构是一个内部结构,保存所打开的目录信息,作用类似于FILE结构
函数出错返回 NULL
#include
#include
#include
#include
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("a.out path\n");
exit(1);
}
DIR* dir = opendir(argv[1]);//打开一个目录
if(dir == NULL)
{
perror("opendir");
exit(1);
}
char buf[512];
getcwd(buf, sizeof(buf));//获取当前进程工作目录
printf("current dir: %s\n", buf);
closedir(dir);//关闭目录
return 0;
}
函数作用:
读目录
头文件:
#include
函数原型:
struct dirent *readdir(DIR *dirp);
函数参数:
dirp:需要读取的目录信息结构体变量
返回值:
返回一条记录项
struct dirent
{
ino_t d_ino; // 此目录进入点的inode
ff_t d_off; // 目录文件开头至此目录进入点的位移
signed short int d_reclen; // d_name 的长度, 不包含NULL 字符
unsigned char d_type; // d_name 所指的文件类型
har d_name[256]; // 文件名
};
d_type成员解释:
DT_BLK - 块设备
DT_CHR - 字符设备
DT_DIR - 目录
DT_LNK - 软连接
DT_FIFO - 管道
DT_REG - 普通文件
DT_SOCK - 套接字
DT_UNKNOWN - 未知
-D_BSD_SOURCE 编译时添加宏定义
#include
#include
#include
#include
//返回传入目录中总共文件数
int get_file_count(char* root)
{
DIR* dir;
struct dirent* ptr = NULL;
int total = 0;
char path[1024];
dir = opendir(root);//打开目录
if(dir == NULL)
{
perror("opendir");
exit(1);
}
while((ptr = readdir(dir)) != NULL)//循环读取目录
{
//过滤掉./和../,因为./是当前目录,../是当前目录
if(strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
{
continue;
}
//文件类型DT_DIR为目录
if(ptr->d_type == DT_DIR)
{
sprintf(path, "%s/%s", root, ptr->d_name);
total += get_file_count(path);
}
//文件类型DT_REG为普通文件
if(ptr->d_type == DT_REG)
{
total ++;//文件累加
}
}
closedir(dir);//关闭目录
return total;
}
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("a.out path\n");
exit(1);
}
int total = get_file_count(argv[1]);//计算传入路径目录中的总文件数
printf("%s has %d files!\n", argv[1], total);
return 0;
}
函数作用:
关闭目录
头文件:
#include
#include
函数原型:
int closedir(DIR *dirp);
函数参数:
dirp:需要关闭的目录信息结构体变量
返回值:
返回0成功;
返回-1失败。
函数作用:
复制现有的文件描述符
头文件:
#include
函数原型:
int dup(int oldfd);
int dup2(int oldfd, int newfd);
函数参数:
oldfd:旧的文件描述符
newfd:新的文件描述符
返回值:
成功返回新的文件描述符;
失败返回-1。
dup2函数说明:
将newfd文件描述符本来指向的文件指向oldfd文件描述符指向的文件,返回当前文件描述符(即现在指向的文件),但是文件描述符的值是不会改变的。
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fd = open("a.txt", O_RDWR);
if(fd == -1)
{
perror("open");
exit(1);
}
printf("file open fd = %d\n", fd);
// 找到进程文件描述表中 ==第一个== 可用的文件描述符
// 将参数指定的文件复制到该描述符后,返回这个描述符
int ret = dup(fd);
if(ret == -1)
{
perror("dup");
exit(1);
}
printf("dup fd = %d\n", ret);
char* buf = "hello world!\n";
char* buf1 = "hello linux!\n";
write(fd, buf, strlen(buf));//写入数据
write(ret, buf1, strlen(buf1));
close(fd);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fd = open("b.txt", O_RDWR);//打开文件
if(fd == -1)
{
perror("open");
exit(1);
}
int fd1 = open("a.txt", O_RDWR);
if(fd1 == -1)
{
perror("open");
exit(1);
}
printf("fd = %d\n", fd);
printf("fd1 = %d\n", fd1);
int ret = dup2(fd1, fd);//将fd文件描述符指向的文件更改成fd1文件描述符指向的文件。
if(ret == -1)
{
perror("dup2");
exit(1);
}
printf("current fd = %d\n", ret);
char* buf = "hello linux!\n";
write(fd, buf, strlen(buf));//向a.txt写入数据
write(fd1, "hello, world!", 13);//向a.txt写入数据
close(fd);//关闭文件
close(fd1);//关闭文件
return 0;
}
函数作用:
根据文件描述符来操作文件的状态
头文件:
#include
函数原型:
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
函数参数:
fd:文件描述符
cmd:
复制一个现有的描述符:F_DUPFD
获得/设置文件描述符标记
F_GETFD
F_SETFD
获得/设置文件状态标记
F_GETFL
只读打开
O_RDONLY
只写打开
O_WRONLY
读写打开
O_RDWR
执行打开
O_EXEC
搜索打开目录
O_SEARCH
追加写
O_APPEND
非阻塞模式
O_NONBLOCK
F_SETFL
可更改的几个标识
O_APPEND
O_NONBLOCK
获得/设置异步I/O所有权
F_GETOWN
F_SETOWN
获得/设置记录锁
F_GETLK
F_SETLK
F_SETLKW
arg:状态设置
返回值:
成功返回当前文件的状态
失败返回-1
#include
#include
#include
#include
#include
int main(void)
{
int fd;
int flag;
// 测试字符串
char *p = "hello linux!";
char *q = "hello world!";
// 只写的方式打开文件
fd = open("test.txt", O_WRONLY);
if(fd == -1)
{
perror("open");
exit(1);
}
// 输入新的内容,该部分会覆盖原来旧的内容
if(write(fd, p, strlen(p)) == -1)
{
perror("write");
exit(1);
}
// 使用 F_GETFL 命令得到文件状态标志
flag = fcntl(fd, F_GETFL, 0);
if(flag == -1)
{
perror("fcntl");
exit(1);
}
// 将文件状态标志添加 ”追加写“ 选项
flag |= O_APPEND;
// 将文件状态修改为追加写
if(fcntl(fd, F_SETFL, flag) == -1)
{
perror("fcntl -- append write");
exit(1);
}
// 再次输入新内容,该内容会追加到旧内容的后面
if(write(fd, q, strlen(q)) == -1)
{
perror("write again");
exit(1);
}
// 关闭文件
close(fd);
return 0;
}
内容很多,未免有疏漏,若是文章中有差错地方,请联系博主更改,也希望本篇文章能给广大网友有所帮助。