Linux基础和Linux下C编程复习总结
- 1. Unix/Linux常见使用和命令
- 2. Working with files and directories
- 3. File and directory permissions
- 4. Linux documentation 帮助
- 5. Editing files -- Vim
- 6. Shell basics
- 7. Working with processes
- 8. Linux utilities
- 9. Shell scripting
- 10. Linux下C编程
写在前面:此文章持续更新,对Linux基础和Linux下C编程的学习进行复习总结。相关学习参考内容已列下方,目前水平有限,如有建议,欢迎指正!
References:
- Linux Basics and Installation Student Notebook
- AIX 5L Application Programming Environment Student Notebook
- Linux编程 天津大学李森
- 黑马程序员Itcast网课
1. Unix/Linux常见使用和命令
-
log in: Ctrl Alt F(2 3 …) 利用不同方式登录系统
-
ifconfig -a
开 ssh 服务 sudo apt install openssh-server
常规用户:$
root用户:#
su命令可以进入root,进入root用su命令也可以回到普通用户。sudo apt install需要让管理员去etc/下的配置文件中加入权限,普通用户便可sudo -
基础命令
command options arguments
命令 选项 参数
# 下面两条who命令体现选项的用法
$ who -m -u
$ who -mu
# Change your password.
$ passwd
# Find out today's date and display a calendar
$ date
$ date +%y%m%d%H%M
$ cal
$ cal 9 1752 特殊
# Find out who else is active on the system
$ who
$ whoami
$ who am i
$ finger
# Clear the screen
$ clear
# Write a message to your own screen.
$ echo
# Write a message to other screens.(单向写)
$ write
# Switch reception of write, wall, and talk messages on or off.
$ mesg
$ mesg n # 关闭 不让人写 除了自己和root
# Write a message to all screens.
$ wall # 广播
# Talk to other users on the system.
$ talk
2. Working with files and directories
-
Unix/Linux万物皆文件:
Ordinary 一般文件
Directory 目录文件
Special file 特殊文件:设备文件(硬件设备)、 逻辑设备 others(sockets、fifos…) -
文件系统想象成一个圆
-
Ide硬盘 : hda hdb
sata, usb硬盘 :sda, sdb
文件名第一个字母是 ‘ . ’ 就是隐含文件 -
Linux 常见目录(没有逻辑盘,文件系统来表示的):
/bin ------ 操作系统命令
/sbin ------ root命令
/lib ------ libra库
/boot ------ linux内核文件
/dev ------ 设备文件
/etc ------ 配置文件
/home ------ 一般用户家目录 登录的初始路径
/root ------ root的家目录
/tmp ------ 进程创建的临时文件(完全权限)
/sys ------ 设备驱动信息 文件系统信息
/proc ------ 内核参数 和 进程的信息(进程号)(内存地址映射)
/usr ------ (unix system resources)所有用户程序
/var ------ 系统的缓冲池(排队文件(emal) 日志 log)
/opt ------ 第三方软件
目录文件、普通文件等操作相关命令
$ ls
$ ls -l # 文件属性详细信息
$ ls -a # 显示所有包含隐藏
$ ls -t # 文件最后一次修改时间排序
$ ls -R # (-R代表递归)
# 目录操作相关
$ cd dir_name
$ cd - # 回到上一次的目录
$ pwd # 打印当前路径
$ mkdir dir_name
$ rmdir #(目录空才能能删)
$ mkdir -p dir1/dir2/dir3
$ rmdir -p dir3/dir2/dir1
$ tree
# 文件操作相关
$ touch # 摸一下文件,不改内容,改时间;若不存在则创建
$ mv source[s] target # 同一个目录下用mv,文件只改名不移动
$ cp source[s] target
$ rm
$ rm -i # 交互式删除,安全
$ rm -r # 猛删
$ rm -rf # r递归 f强制。最危险
# Linux的rm不可逆(删除的是inode表里的inode信息)
# 文件内容相关
$ vi # 默认vim,著名编辑器
$ cat
$ more
$ less
$ head
$ tail
$ tail –f # 一直跟踪文件末尾,查看log以及调试
$ od # 看二进制文件
$ strings # 从二进制文件里提出来字符串
# 统计信息相关
$ wc # word count
- 软硬连接
5.1 硬连接hard link (找inode号)
引用的同一个磁盘块,和copy不一样(copy的话内容复制一份了)
删除时:连接数大于1,把目录登记项清楚了 连接数减1;连接数为1,就到了free list inode里,相当于猛删了。
$ ln a b
5.2 软连接soft link(类似快捷方式)(符号连接,找名儿)
删了就报错了,就找不到了,变红了
$ ls -s a aa
- 文件系统挂在操作系统的目录树
3. File and directory permissions
若对目录有写和执行权
则 rm删除(目录下)文件、mv(目录下)文件 什么权限都不需要
如何防止删库跑路:对公共目录加t权限
- 修改权限
$ chmod
- umask(跟子网掩码的运算像)
4. Linux documentation 帮助
# 三种查帮助方式
$ man # 查命令帮助、查询手册
$ man write # 直接查
$ man 2 write # 按分册查
$ man man
$ info ls
$ ls --help
5. Editing files – Vim
(Vim相关只列出部分知识总结,因其用法较多且有许多文章,在此不多赘述)
vi in linux is usually vim
vim有命令模式与编辑模式
vim可以自己写配置文件 保存你常用的set
- 编辑模式与命令模式的切换
- 命令模式下编辑文本
- 退出方式
6. Shell basics
The shell is the user interface to Linux.
通配符:
‘’ 单引号可以屏蔽里面所有元字符特殊含义
文件描述符(文件句柄):
| pipes管道符:
多个命令连在一起用,左边命令的输出全部传到右边的命令(进程间通信,无名管道)
Filters 过滤器:
A filter is a command that reads from standard in, transforms the input in some way, and writes to standard out. They can, therefore, be used at intermediate points in a pipeline.(帮管道筛选)
如: ls | grep .doc | wc -l
过滤器通常与管道一起使用,如上面的示例所示。ls命令列出当前目录中的所有文件,然后将这些信息传输到grep命令。grep的输出通过管道传输到wc -l命令。结果是该命令对当前目录中包含.doc的文件数量进行计数。在本例中,grep命令充当过滤器。
$()-----括号里的字符串为命令
;-----一次性提交一组命令
()-----起一个子shell,对当前shell无影响
{}-----和不加一样,对当前shell有影响
用户写变量尽量写小写变量
The alias command allows you to set up aliases for often-used commands.(定义自己常用的命令)
7. Working with processes
当运行敲进去ls,ls这个命令(进程)是被shell窗口提交的
The ps command displays process status information.
ps supports a large number of options; you typically use ps aux.
$ps aux | grep XXX
pstree shows process hierarchy.
$pstree -p XXX (看线程)
前台进程与后台进程
前台进程:(目前常用)shell会被阻塞,shell不能做其他
后台进程:(正常命令后加个“ &”)一个bash可以多个后台进程,要求后台进程不能交互,标准输出要做定向
信号 Kill signals
kill是给进程发信号,不能完全理解成杀死,只不过大部分kill命令是让终止的。kill对应的函数是signal。有的程序可以设置屏蔽好几个kill信号,但9号信号不能被屏蔽,直接终止了。非root只能向自己的进程发信号。
3号信号 会保存core dump. End process and core dump
$ nohup
脚本用nohup执行(一定要加个”&”作为后台进程,还要做>>定向输出),不受当前shell窗口关闭影响,会忽略一号信号(关闭中断,在这个中断下的子进程全over)。
典型的例子是跑python的训练神经网络代码用这个。
进程调度是按优先级调度的
$ ps -l (看优先级)
PRI值是优先级
$ nice (一般用户只能增大nice,优先级变低,root可以降低pri,优先级变高)
$ renice (运行后改优先级)
8. Linux utilities
$find (递归查找文件之类)
$find . -name XXX
$find ./ -type d | xargs ls –l
(xargs分成 块 传递给ls –l ,不会溢出)
xargs find好伴侣,将find查到的结果分成若干块输出给后面的指令。
The -ok option also causes command execution but on an interactive basis.(交互模式,提问y/n,安全模式)
$grep (对文件里的内容进行查找,内容过滤)
Searches one or more files or standard input for lines matching a pattern.
Syntax:
–grep [options] pattern [file1 …]
grep的pattern可以用正则表达式,注意需要用 ’ ’ 来括住regex,这样可以屏蔽shell对它解释。
$sort (按某种要求给排序,默认是字典排序,从小到大)
$tail
The tail command displays the last few lines of a file or files.
$ tail -f XXX.log (实时看到文件变化,看日志文件输出)
9. Shell scripting
命令组成的文本文件叫shell脚本
运行脚本有三种方式:
-
$bash script
脚本需要可读,不是必须有可执行权,在子shell里执行 -
$./script ---- run in child shell.(和上面的一样)
若对该文件chmod,有执行权后,对shell脚本文件当成命令运行。 -
$. script
$ source script
use dot or source command to execute the script in your current shell environment.
(脚本执行完后当前bash有定义好的变量(在当前bash运行脚本,而不是子shell里运行脚本))同样此时脚本也需要有执行权
To make sure the shell script always runs in the shell it was intended for (sh, bash, csh), use the following on the first line of your script:
#!/bin/bash
(写shell脚本的开头)
可以定制自己的bash环境(给一些命令起别名等等)
10. Linux下C编程
10.1 overview and compiling program
解释执行:脚本
编译执行:c/c++
-
预处理阶段(预处理器cpp):处理以 # 开头的预处理命令;
-
编译阶段(编译器):翻译成汇编文件;
-
汇编阶段(汇编器):将汇编文件翻译成可重定向目标文件(二进制);
-
链接阶段(链接器):将可重定向目标文件和 printf.o 等单独预编译好的目标文件进行合并,得到最终的可执行目标文件。
10.2 overview of gcc and gdb
Linux上用gcc做编译器(编译链接)
Linux上调试用gdb调试
gcc 的不同选项:
头文件路径没有,指定一下包含的头文件路径
(#include “”)
$ gcc add.c –I ./include
$ gcc add.c –I ./include -o app
$g++ (可以用来编译c++代码)
gdb调试
编译时需要添加 –g 选项
core文件:通常情况下,core文件会包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息还有各种函数调用堆栈信息等,我们可以理解为是程序工作当前状态存储生成第一个文件,许多的程序出错的时候都会产生一个core文件,通过工具分析这个文件,我们可以定位到程序异常退出的时候对应的堆栈调用等信息,找出问题所在并进行及时解决。
Core Dump,程序执行出错了,程序员可以看这个东西。(process保护现场信息等)
10.3 makefile
makefile三要素:目标,依赖,规则命令
写法:
目标:依赖
tab键规则命令
规则是递推的,若多加几层递推可以使比如某个文件改了只需重新编译这个改了的这个文件。
目标文件用法
优化makefile编写方式
对上一步进行模式推导变量
清理文件
当有一个clean的文件时,再次make clean,因为clean作为目标没有更新,make clean就不执行了。解决方法,伪目标(伪目标还可以用来比如要用一个makefile编译三个可执行文件,见linux project大作业)
10.4 system call introduction
系统API与库函数的关系:
系统API:system call
库函数:printf();
内核接口:
Memory Management 内存管理
malloc与free
Java: jvm里自动回收垃圾机制,可以不管内存分配
c/c++: 申请内存,谁分配谁释放
10.5 FILE and I/O System Calls
lseek()
1.移动文件的读写位置
(解决了写完后,文件读写位置到达了末尾的问题)
2.计算文件大小
3.拓展文件
(在磁盘里拓展出1024大小的)
文件映射到内存
读写文件,留一块文件的内存,因为磁盘读写太慢。读一个文件时,读第一行,把第二行三行也缓存到内存了。
首先,通过分配一个文件描述符(显示在用户区域的左侧,指向磁盘文件),以正常方式打开该文件。接下来,程序执行一个shmat()系统调用(共享内存附加)来获取由内核分配给文件的段,并将它映射到进程的一个段。一旦文件被映射到进程的虚拟内存边界中,进程就可以直接在内存中访问文件中的数据,而不用使用read()和write()调用。
errno
stat 可以实现查询inode的属性信息(实现ls -l)
dup2 重定向(改变句柄指向,比如,文件描述符1本来指着设备文件,可以改成指向其他文件)(输出到屏幕上,其实就是输出到设备文件里,linux万物皆文件)
dup可以复制文件描述符
系统调用之文件锁:系统提供了文件锁的系统调用,防止多人写情况。
文件锁(和读写锁差不多,只不过是进程的,创建了个temp.lock的文件)(当前系统,这个进程只能起一个)
10.6 Process Management System Calls
一个进程最多打开ulimit -a个文件。(文件描述符表,一个进程默认一开始打开0 1 2的文件描述符(句柄)已经被占了,即标准输入输出)
进程虚拟地址空间,进程的用户态(代码全局堆栈…),内核态(进程管理、PCB、内存管理、虚拟文件系统…)
If (fork() == 0) {代表在子进程里的执行逻辑}
fork创建子进程,返回值-1代表失败,返回值0代表子进程,返回值大于0代表目前在父进程
MMU的作用:虚拟内存和物理内存的映射
PCB在代码中表现就是个结构体:struct task_struct
环境变量是keyvalue的方式(可以通过配置文件配置环境变量)
进程控制
fork()调用后子进程父进程就开始分叉
循环创建子进程(注意为什么要break,因为不break会造成子进程也继续生子进程)
The exec System Calls ---- exec族函数
Upon completion of the fork() system call, both the parent and the child processes are
running the same code. This is often not what is wanted. Another system call is used to load and execute a new program in the process. The exec family of system calls is used to replace the calling process’ text and data regions with new program code and data.
10.6.1 孤儿进程
所谓孤儿进程,因为父进程先死了。
孤儿进程:父亲死了,子进程被init进程领养。(init进程号称孤儿院)
(因为父进程是shell fork出来,再fork产生孤儿进程后,用ctrl c杀不死这个孤儿进程了,因为脱离了shell了,得用kill -9杀)
10.6.2 僵尸进程
僵尸进程:子进程死了,父进程没有回收子进程的资源(PCB)
若已经产生僵尸进程后,回收僵尸进程:杀死父进程,init领养,负责回收。
正常情况下,父进程回收子进程的方法(为什么必须父进程回收,因为操作系统默认父进程回收,内核不负责回收):
- 用wait():阻塞等待,回收子进程资源
用waitpid():可以不阻塞回收 - 程序中显示的调用signal(SIGCHLD, SIG_IGN)来忽略SIGCHLD信号,这样子进程结束后,由内核来wait和释放资源(不用阻塞等待)
- 父进程fork再fork,第一个fork立马退出,第二个fork变成孤儿进程,就不会是僵尸进程了
10.7 Signal Management
信号的系统调用:
kill()
signal()
sigaction()
10.8 IPC(Inter-process Management)
System V IPC
Shared Memory 共享内存:用来交换数据,可将共享内存与进程内存地址空间进行连接。
Semaphores 信号量:单个信号量or信号量集,原子操作,同步问题。
Message queues 消息队列:服务端客户端。
系统对IPC通信的对象进行编号 IPC keys
B找123(因为,ab通信,已经协商了IPC keys)IPC keys用来找对应的创建的ipcs
详细编程代码逻辑请看linux project,用到了信号量和消息队列以及多线程同步、守护进程等等
socket(此部分内容正在学习,学习完unix网络编程上传此部分详细学习总结)
传统简易用法:服务器端负责监听,然后创建子进程(现在都是创建线程) 与客户端通信。简易socket系统调用如下:
10.9 Daemons 守护进程
(进程组往上一级是会话,会话是多个进程组组成的)
Daemon Example(更多详细过程移步linux project)
10.10 RPC
RPC(Remote Procedure Call) ---- 远程过程调用
传的是函数(分布式、并行计算)
10.11 Threads 线程及多线程
线程(#include <pthread.h>)
使用线程库gcc指定 -lpthread
也要避免僵尸线程:
pthread_join() 用来回收线程
pthread_detach()(线程分离)不用自己回收线程,os回收
线程对信号支持不好
创建多少个线程:cpu核数*2+2
10.11.1 线程同步
- 互斥锁/互斥量(Mutex)
加锁,当有线程已经加锁的时候会阻塞。
典型加锁过程:
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
死锁之交叉锁:
解决:规定申请锁的顺序要一致;如果申请到一把锁,申请另外一把锁的时候申请失败,应该释放已经掌握的。
- 读写锁
读写锁的使用场景:适合读的线程多。
pthread_rwlock_ 簇
下图体现出写的优先级高(与之前操作系统文章进程同步那块读者优先的不一样了,可以结合着看体会)
- 条件变量
可以引起阻塞,并非锁,要和互斥锁组合使用。
pthread_cond_ 簇
- 信号量
这里的信号量是库函数,不是系统调用。同时支持线程和进程。
可以理解是加强版的互斥锁,当信号量为1时候,退化为互斥锁。
sem_ 簇
#include <semaphore.h>
post是++,wait是–
在生产者消费者模型中,信号量其实是消费者和生产者互相通知的过程,即p的和v的东西不同。