目录
获取子进程退出值和异常终止值——进一步理解fork函数工作方式
黑马课程学习
文件,目录,目录项,文件描述符
在linux中,所见皆文件,目录也可以看作是一种特殊的文件,目录文件中保存了该目录下的子目录以及子文件这两者的目录项信息。
不那么准确的说,一个文件通常会涉及到三个部分的数据,索引节点(inode),目录项(dentry)以及在硬盘中文件的本体信息。
索引节点,也就是 inode,用来记录文件的元信息,比如 inode 编号、文件大小、访问权限、创建时间、修改时间、数据在磁盘的位置等等。索引节点是文件的唯一标识,它们之间一一对应,也同样都会被存储在硬盘中,所以索引节点同样占用磁盘空间。
目录项,也就是 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的层级关联关系。多个目录项关联起来,就会形成目录结构,但它与索引节点不同的是,目录项是由内核维护的一个数据结构,不存放于磁盘,而是缓存在内存。
由于索引节点唯一标识一个文件,而目录项记录着文件的名,所以目录项和索引节点的关系是多对一,也就是说,一个文件可以有多个目录项。比如,硬链接的实现就是多个目录项中的索引节点指向同一个文件。
下图很好的展示了索引节点,目录项以及文件数据的关系
注意:目录与目录项,虽然名字很相近,但是它们不是一个东西,目录是个文件,持久化存储在磁盘,而目录项是内核一个数据结构,缓存在内存。
关于文件描述符:
在linux中,内核为使当前进程与进程打开的文件建立联系,每一个进程都会维护一个PCB(process control block)进程控制块。在PCB中保存着一份文件描述表,文件描述符就是这个表的索引,记录了进程所用到的各个文件的信息。
用fork函数循环创建多个子进程
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新子进程中,相当于克隆了一个自己。父进程和子进程都会收到一个关于fork函数的返回值,父进程的得到的返回值是子进程的进程id,子进程得到的返回值统一是0;
如下图,在执行完fork函数之后,会产生一个新的子进程,此时父进程和子进程都从fork()函数的下一句开始执行,而此时下一句是判断进程id号的语句,它的作用是如果当前的进程id号为0(即当前进程是子进程)就直接退出for循环,所以在进入子进程后,子进程只会执行下面的打印函数。下面的if判读语句通过i值判断当前进程是父进程还是子进程。此外sleep函数是用于调整几个进程打印函数的调用顺序。注意sleep函数的放置位置。
父进程与子进程关于全局变量
遵循读时共享,写时复制的原则,即父进程和子进程在读全局变量时,并不会对全局变量改变,而对全局变量执行写操作时,会将全局变量复制一份到本进程中去进操作,对原来的全局变量也不会造成影响。
获取子进程退出值和异常终止值——进一步理解fork函数工作方式
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void){
pid_t pid, wpid;
int status;
pid = fork();
//在执行fork函数之后,子进程和父进程都会执行下面的代码,所以用if判断语句
//来根据不同进程的pid号,对不同的进程执行不同的操作
if (pid == 0) {
printf("---child, my id= %d, going to sleep 10s\n", getpid());
sleep(10);
printf("-------------child die--------------\n");
return 73;
}
else if (pid > 0) {
//wpid = wait(NULL); 不关心子进程结束原因
wpid = wait(&status);// 如果子进程未终止,父进程阻塞在这个函数上
if (wpid == -1) {
perror("wait error");
exit(1);
}
if (WIFEXITED(status)) { //为真,说明子进程正常终止.
printf("child exit with %d\n", WEXITSTATUS(status));
}
if (WIFSIGNALED(status)) {//为真,说明子进程是被信号终止.
printf("child kill with signal %d\n", WTERMSIG(status));
}
printf("------------parent wait finish: %d\n", wpid);
}
else {
perror("fork");
return 1;
}
return 0;
}
循环遍历目录 实现ls功能
需要用到对目录的操作函数 opendir() readdir() closedir() 以及对文件的操作函数 stat()。
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
void isfile(char *);
//打开目录,处理目录
void read_dir(char * dir){
char path[256];
DIR * dp;
struct dirent * sdp;
dp = opendir(dir);
if(dp == NULL){
perror("opendir error");
return;
}
while((sdp = readdir(dp))){
//避免重复遍历,将出现当前目录和上一级目录的情况排除
if(!strcmp(sdp->d_name,".")||!strcmp(sdp->d_name,"..")) continue;
//应当输入绝对路径,将两个字符串拼接
sprintf(path,"%s/%s",dir,sdp->d_name);
isfile(path);
}
closedir(dp);
}
//判断当前文件是目录文件还是文本文件
void isfile(char * name){
struct stat sbuf;
int ret = 0;
ret = stat(name,&sbuf);
if (ret==-1){
perror("stat error");
return;
}
if(S_ISDIR(sbuf.st_mode)) read_dir(name);
else printf("file size: %6ld,\tfile name: %s\n",sbuf.st_size,name);
}
int main(int argc,char * argv[]){
if(argc == 1) isfile(".");//如果没有参数输入,默认表示当前目录
else isfile(argv[1]);
return 0;
}
dup和dup2函数
这两个函数用于重定向,本质是文件描述符的复制。其中dup2可以自己指定文件描述符,而dup函数只能由系统分配。顾名思义,重定向就是将newfd重定向到oldfd上,将对newfd的操作转到oldfd上。
int dup(int oldfd); //oldfd: 已有文件描述符 返回:新文件描述符
int dup2(int oldfd, int newfd); //oldfd 拷贝给 newfd。返回 newfd
int fd1 + open(a.txt,O_RDWR);
int fdnew = dup(fd1, STDOUT_FILENO);//此条语句就是将标准输出文件重定向到a.txt上,
//将原本要输出到屏幕上的文件输出到a.txt中。
管道的使用
管道本质是一个伪文件(实为内核缓冲区)
函数 int pipe(int fd[2]) 用于创建并打开管道(即该命令包含了open命令),创建成功后 pipe 函数的输出参数为两个文件描述符:一个为读端文件描述符,一个为写端文件描述符,这两个参数保存在fd[2]数组中。该函数返回值表示管道的创建情况,返回0表示创建成功,返回-1表示创建失败。默认管道的缓冲区大小为4KB
fd[0]代表读端文件描述符 这里的 读 指的是,进程从管道中读取数据
fd[1]代表写端文件描述符 这里的 写 指的是,进程向管道中写入数据
当一个父进程或子进程对管道进行读操作(或写操作)时,需要用close函数将该进程对管道文件的写操作(或读操作)文件描述符关闭。
管道的读写行为
读管道:
管道有数据,read 返回实际读到的字节数。
管道无数据:
- 无写端,read 返回 0 (类似读到文件尾)
- 有写端,read 阻塞等待。
写管道:
无读端, 异常终止。 (SIGPIPE 导致的)
有读端:
- 管道已满, 阻塞等待
- 管道未满, 返回写出的字节个数。
用匿名管道实现兄弟进程之间的通讯
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc,char * argv[])
{
int ret,i;
pid_t pid;
int fd[2];
ret = pipe(fd);//打开管道文件 两个相关的文件描述符被保存在fd数组中
if(ret == -1){
perror("pipe error");
exit(1);
}
for(i=0;i<2;i++){
pid = fork();
if(pid == 0) break;
}
if(i == 2){
close(fd[0]);
close(fd[1]);
while(waitpid(-1,NULL,0) != -1) {}
}
else if( i==0 ){
dup2(fd[1],STDOUT_FILENO);//原本是要向标准输出中写入数据,重定向使数据写入到管道写端
close(fd[0]);//fd[0]代表读端文件描述符
execlp("ls","ls",NULL);
perror("exec error");
}
else if(i == 1 ){
dup2(fd[0],STDIN_FILENO);//原本是要从标准输入中读取数据,重定向使从管道读端中读取数据
close(fd[1]);//fd[1]代表写端文件描述符
execlp("wc","wc","-l",NULL);
perror("exec error");
}
return 0;
}
信号的工作原理
ps aux
ps命令是Process Status的缩写。ps命令用来列出系统中当前运行的那些进程
参数 | 作用 |
-a | 显示所有进程(包括其他用户的进程) |
-u | 用户以及其他详细信息 |
-x | 显示没有控制终端的进程 |
-j | 显示父进程,组进程,会话的编号 |
关于互斥锁的小理解
官方说法:在编程中,用互斥锁来保证共享数据操作的完整性,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量。对互斥量进行上锁以后,其他试图再次对互斥量加锁的线程都会被阻塞直到当前线程释放该互斥锁。
其实简单来说,可以把互斥锁看作是两个线程共有的一个变量,它是一个标志,代表当前是否有线程要对某一资源进行访问,但是互斥锁并不是真正对资源上锁,它只能说是一个建议量,如果线程绕过互斥量直接对资源进行访问,还是保证不了线程的同步。
互斥锁能够起到作用的前提是:线程严格按照互斥锁的操作步骤来进行(即先申请上锁,操作完资源后解锁)。下面对互斥锁的上锁和解锁进行详细说明:
一个进程想对互斥量进行加锁操作,即该进程想独占某个资源,不想让其他线程访问到,如果此时已经有其他线程调用了上锁函数对互斥量进行了上锁,那么此时该线程只能阻塞等待持有该互斥锁的进程解锁为止;如果此时互斥锁未上锁,则该进程对互斥量上锁。
一个进程相对互斥量进行解锁操作,代表着该进程使用完某资源,将不再独占它,此时它会将所有阻塞在该锁上的线程全部唤醒,接着由cpu来决定哪个线程可以再次对互斥量进行上锁。
几个退出函数
exit(); 退出当前进程。
return: 返回到调用者那里去。
pthread_exit(): 退出当前线程。
read函数返回值
read 函数返回值:
> 0: 实际读到的字节数=0: socket中,表示对端关闭。close()
-1:
如果 errno == EINTR 被异常终端。 需要重启。
如果 errno == EAGIN 或 EWOULDBLOCK 以非阻塞方式读数据,但是没有数据。需要再次读。
如果 errno == ECONNRESET 说明连接被 重置。 需要 close(),移除监听队列。
其他情况,错误
信号与信号量
信号与信号量是完全不同的概念
信号:是由用户、系统或者进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常。
信号量:信号量是一个特殊的变量,它的本质是计数器,信号量里面记录了临界资源的数目,有多少数目,信号量的值就为多少,进程对其访问都是原子操作(pv操作,p:占用资源,v:释放资源)。它的作用就是,调协进程对共享资源的访问,让一个临界区同一时间只有一个进程在访问它。
所以它们两的区别也就显而易见了,信号是通知进程产生了某个事件,信号量是用来同步进程的
零碎知识
常用工具 tldr Tmux
库函数 readline strtok sscanf
必须要掌握的
- 文件管理 -
cd
,pwd
,mkdir
,rmdir
,ls
,cp
,rm
,mv
,tar
- 文件检索 -
cat
,more
,less
,head
,tail
,file
,find
- 输入输出控制 - 重定向, 管道,
tee
,xargs
- 文本处理 -
vim
,grep
,awk
,sed
,sort
,wc
,uniq
,cut
,tr
- 正则表达式
- 系统监控 -
jobs
,ps
,top
,kill
,free
,demsg
,lsof
linux目录符号
/:代表着根目录,是树形结构的最上层;
.:表示当前目录,也可以用./表示;
. .:表示上一级目录,也可以用. ./表示;
~:代表用户自己的家目录;
Linux系统文件类型: 7/8 种
linux中万物皆可视为文件,并且对于文件的分类不看其后缀名,而是看文件的类型。
普通文件:-
目录文件:d
字符设备文件:c
块设备文件:b
软连接:l
管道文件:p
套接字:s
未知文件。
配置VIm
键入如下指令:
cp /etc/vim/vimrc ~/.vimrc
cd ~
ls -a
vim .vimrc
打开.vimrc文件后,按下面所示修改文件,以下语法是一种diff的上下文格式
--- before modification
+++ after modification
@@ -17,3 +17,3 @@
" Vim5 and later versions support syntax highlighting. Uncommenting the next
" line enables syntax highlighting by default.
-"syntax on
+syntax on
@@ -21,3 +21,3 @@
" If using a dark background within the editing area and syntax highlighting
" turn on this option as well
-"set background=dark
+set background=dark
@@ -31,5 +31,5 @@
" Uncomment the following to have Vim load indentation rules and plugins
" according to the detected filetype.
-"filetype plugin indent on
+filetype plugin indent on
@@ -37,10 +37,10 @@
" The following are commented out as they cause vim to behave a lot
" differently from regular Vi. They are highly recommended though.
"set showcmd " Show (partial) command in status line.
-"set showmatch " Show matching brackets.
-"set ignorecase " Do case insensitive matching
-"set smartcase " Do smart case matching
-"set incsearch " Incremental search
+set showmatch " Show matching brackets.
+set ignorecase " Do case insensitive matching
+set smartcase " Do smart case matching
+set incsearch " Incremental search
"set autowrite " Automatically save before commands like :next and :make
-"set hidden " Hide buffers when they are abandoned
+set hidden " Hide buffers when they are abandoned
"set mouse=a " Enable mouse usage (all modes)
附上其他的一些选项,按需开启
set lines=22 columns=70 " 设置窗口大小
winpos 5 5 " 设置窗口位置
setlocal noswapfile " 不要生成swap文件
set bufhidden=hide " 当buffer被丢弃的时候隐藏它
colorscheme evening " 设定配色方案
set number " 显示行号
set cursorline " 突出显示当前行
set ruler " 打开状态栏标尺
set shiftwidth=4 " 设定 << 和 >> 命令移动时的宽度为 4
set softtabstop=4 " 使得按退格键时可以一次删掉 4 个空格
set tabstop=4 " 设定 tab 长度为 4
set nobackup " 覆盖文件时不备份
set autochdir " 自动切换当前目录为当前文件所在的目录
set backupcopy=yes " 设置备份时的行为为覆盖
set hlsearch " 搜索时高亮显示被找到的文本
set noerrorbells " 关闭错误信息响铃
set novisualbell " 关闭使用可视响铃代替呼叫
set t_vb= " 置空错误铃声的终端代码
set matchtime=2 " 短暂跳转到匹配括号的时间
set magic " 设置魔术
set smartindent " 开启新行时使用智能自动缩进
set backspace=indent,eol,start " 不设定在插入状态无法用退格键和 Delete 键删除回车符
set cmdheight=1 " 设定命令行的行数为 1
set laststatus=2 " 显示状态栏 (默认值为 1, 无法显示状态栏)
set statusline=\ %<%F[%1*%M%*%n%R%H]%=\ %y\ %0(%{&fileformat}\ %{&encoding}\ Ln\ %l,\ Col\ %c/%L%) " 设置在状态行显示的信息
set foldenable " 开始折叠
set foldmethod=syntax " 设置语法折叠
set foldcolumn=0 " 设置折叠区域的宽度
setlocal foldlevel=1 " 设置折叠层数为 1
nnoremap <space> @=((foldclosed(line('.')) < 0) ? 'zc' : 'zo')<CR> " 用空格键来开关折叠
GCC编译的4步骤
其中 gcc -o 指令是用于指定生成文件的名字的,没有其他的作用
创建一个.c文件并编译执行
$ mkdir swp //在当前文件夹下创建swp文件夹
$ cd swp //进入swp文件夹内部
$ pwd
/home/wning/swp //显示当前路径
$ vi hello.c //创建hello.c文件并用vim打开,写入程序
$ gcc hello.c -o hello //gcc的-o选项指定了输出文件的名称, 如果将-o hello改为-o hi,
//将会生成名为hi的可执行文件. 如果不使用-o选项,
//则会默认生成名为a.out的文件
$ ./hello // 运行, ./hello表示当前目录下的hello文件
gcc用于编写C语言的文件;g++用于编写c++的文件。
LINUX基本命令和文件格式
Linux常用命令_Demon的博客-CSDN博客_linux常用命令
目录操作命令
./* 当前文件夹下所有文件
1 目录切换 cd
命令:cd 目录
cd / 切换到根目录
cd /usr 切换到根目录下的usr目录
cd ../ 切换到上一级目录 或者 cd ..
cd ~ 切换到home目录
cd - 切换到上次访问的目录
2 目录查看 ls [-al]
命令:ls [-al]
ls 查看当前目录下的所有目录和文件
ls -a 查看当前目录下的所有目录和文件(包括隐藏的文件)
ls -l 或 ll 列表查看当前目录下的所有目录和文件(列表查看,显示更多信息)
ls -hl 查看详细信息并以可读大小显示文件大小
ls /dir 查看指定目录下的所有目录和文件 如:ls /usr
3 目录操作
创建目录
命令:mkdir 目录
mkdir aaa 在当前目录下创建一个名为aaa的目录
mkdir /usr/aaa 在指定目录下创建一个名为aaa的目录
删除目录或文件
命令:rm [-rf] 目录
删除文件:
rm 文件 删除当前目录下的文件
rm -f 文件 删除当前目录的的文件(不询问)
删除目录:
rm -r aaa 递归删除当前目录下的aaa目录
rm -rf aaa 递归删除当前目录下的aaa目录(不询问)
全部删除:
rm -rf * 将当前目录下的所有目录和文件全部删除
rm -rf /* 【自杀命令!慎用!慎用!慎用!】将根目录下的所有文件全部删除
注意:rm不仅可以删除目录,也可以删除其他文件或压缩包,为了方便大家的记忆,无论删除任何目录或文件,都直接使用 rm -rf 目录/文件/压缩包
目录修改 mv 和 cp
一、重命名目录
命令:mv 当前目录 新目录
例如:mv aaa bbb 将目录aaa改为bbb
注意:mv的语法不仅可以对目录进行重命名而且也可以对各种文件,压缩包等进行 重命名的操作二、剪切目录
命令:mv 目录名称 目录的新位置
示例:将/usr/tmp目录下的aaa目录剪切到 /usr目录下面 mv /usr/tmp/aaa /usr
注意:mv语法不仅可以对目录进行剪切操作,对文件和压缩包等都可执行剪切操作三、拷贝目录
命令:cp -r 目录名称 目录拷贝的目标位置 -r代表递归
示例:将/usr/tmp目录下的aaa目录复制到 /usr目录下面 cp /usr/tmp/aaa /usr
注意:cp命令不仅可以拷贝目录还可以拷贝文件,压缩包等,拷贝文件和压缩包时不 用写-r递归搜索目录 find
命令:find 目录 参数 文件名称
示例:find /usr/tmp -name 'a*' 查找/usr/tmp目录下的所有以a开头的目录或文件
新建文件 touch
命令:touch 文件名
示例:在当前目录创建一个名为aa.txt的文件 touch aa.txt删除文件 rm
命令:rm -rf 文件名
VIM的使用
vim分为三种状态,分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:
1) 命令行模式
控制屏幕光标的移动,字符、字或行的删除,查找,移动复制某区段及进入Insert mode下,或者到 last line mode。
命令行模式下的常用命令:
- 控制光标移动:↑,↓,j
- 删除当前行:dd
- 查找:/字符
- 进入编辑模式:i o a
- 进入底行模式::
- 切换到最后一行:G
- 切换到第一行:gg或1G
- 切换到第n行:nG
- 删除光标所在行:dd
- 复制光标所在行:yy
- 粘贴于光标之后:p
- 删除所有行:ggdG
2) 编辑模式(Insert mode)
只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。
编辑模式下常用命令:
【1】ESC 退出编辑模式到命令行模式;
3) 底行模式(last line mode)
将文件保存或退出vi,也可以设置编辑环境,如寻找字符串、列出行号……等。
底行模式下常用命令:
【1】退出编辑: :q
【2】强制退出: :q!
【3】保存并退出: :wq打开文件
命令:vi 文件名
示例:打开当前目录下的aa.txt文件 vi aa.txt 或者 vim aa.txt
编辑文件:使用vi编辑器打开文件后点击按键:i ,a或者o即可进入编辑模式。
i:在光标所在字符前开始插入
a:在光标所在字符后开始插入
o:在光标所在行的下面另起一新行插入 底行模式可用命令
:w //保存
:wq //保存并退出
:q! //不保存直接退出
:set nu //显示行号
:set nonu //不显示行号
:s/one/two //将当前光标所在行的第一个one替换成two
:s/one/two/g //将当前光标所在行的所有one替换成two
:%s/one/two/g //将文中所有one替换成two
vim下字符串的查找
/+ 要查找的字符串,按下回车即可自当前光标位置向上开始查找,按下n或N可以切换下一个。(n,继续朝同一方向搜索 ;N,反方向进行搜索。)
若要自当前光标位置向下搜索 用?+要查找的字符串
vim与fzf的结合使用
fzf是一个模糊搜索插件,结合vim使用,可以很方便的浏览当前文件夹下的文件并进入编辑。
vim $(fzf)
在Linux下使用vim配合xxd查看并编辑二进制文件 - killkill - 博客园
学习截图及笔记
人类不可读版 (STFW: clockwise/spiral rule)
void (*signal(int sig, void (*func)(int)))(int);
人类可读版
typedef void (*sighandler_t)(int);
sighandler_t signal(int, sighandler_t);//函数signal返回一个函数指针,参数为一个int
//和一个函数指针
计算机是个状态机
既然计算机是一个数组逻辑电路, 那么我们可以把计算机划分成两部分, 一部分由所有时序逻辑部件(存储器, 计数器, 寄存器)构成, 另一部分则是剩余的组合逻辑部件(如加法器等). 这样以后, 我们就可以从状态机模型的视角来理解计算机的工作过程了: 在每个时钟周期到来的时候, 计算机根据当前时序逻辑部件的状态, 在组合逻辑部件的作用下, 计算出并转移到下一时钟周期的新状态.
我们知道程序是由指令构成的, 那么我们先看看一条指令在状态机的模型里面是什么. 不难理解, 计算机正是通过执行指令的方式来改变自身状态的, 比如执行一条加法指令, 就可以把两个寄存器的值相加, 然后把结果更新到第三个寄存器中; 如果执行一条跳转指令, 就会直接修改PC的值, 使得计算机从新PC的位置开始执行新的指令. 所以在状态机模型里面, 指令可以看成是计算机进行一次状态转移的输入激励.
统计磁盘使用情况
以下命令统计/usr/share
目录下各个目录所占用的磁盘空间:
du -sc /usr/share/* | sort -nr
du
是磁盘空间分析工具, du -sc
将目录的大小顺次输出到标准输出, 继而通过管道传送给sort
. sort
是数据排序工具, 其中的选项-n
表示按照数值进行排序, 而-r
则表示从大到小输出. sort
可以将这些参数连写在一起.然而我们发现, /usr/share
中的目录过多, 无法在一个屏幕内显示. 此时, 我们可以再使用一个命令: more
或less
.
du -sc /usr/share/* | sort -nr | more
此时将会看到输出的前几行结果. more
工具使用空格翻页, 并可以用q
键在中途退出.
统计当前目录下中(包含子目录)中以.c
和.h
结尾的文件的代码行数
写法一:
find . | grep '\.c$\|\.h$' | xargs wc -l
写法二:
$ find . -name "*.c" -o -name "*.h" | xargs cat | wc -l
其中find命令中的 -o 表示或,类似的 -a 表示且, -not 表示非
GDB(the GNU debugger)GDB调试指南(入门,看这篇够了)_chen1415886044的博客-CSDN博客_gdb 调试
编译并启动gdb:
gcc -g test.c -o test
gdb test//test为编译好的二进制文件
常用命令:
Next和Step的区别
通常情况下,step 命令和 next 命令的功能相同,都是单步执行程序,但当遇到包含调用函数的语句时,无论函数内部包含多少行代码,next 指令都会一步执行完。也就是说,对于调用的函数来说,next 命令只会将其视作一行代码。 step 命令,会进入该函数内部,并在函数第一行代码处停止执行。
continue:继续执行,到下一个断点处(或运行结束)
常用命令
cat //查看命令,用于输出文件内容到Terminal
$ cat /etc/locale.gen // 输出 locale.gen 的内容
$ cat -n /etc/locale.gen // 输出 locale.gen 的内容并显示行号
more //与cat相似,都可以查看文件内容,所不同的是,当一个文档太长时,
//cat只能展示最后布满屏幕的内容,前面的内容不可见,此时可用more逐行显示内容。
$ more /etc/locale.gen
$ more +100 /etc/locale.gen // 从 100 行开始显示
less //与more相似,不过less支持上下滚动查看内容,而more只支持逐行显示。
$ less /etc/locale.gen
$ less +100 /etc/locale.gen
grep // global search regular expression 用于搜索并返回匹配的项目,支持正则表达式。
$ grep PATTERN filename // 返回所有含有 PATTERN 的行
$ grep zh_CN /etc/locale.gen // 返回所有含 zh_CN 的行
whereis //用于查找文件、手册等。
$ whereis bash
bash: /usr/bin/bash /etc/bash.bashrc /etc/bash.bash_logout
/usr/share/man/man1/bash.1.gz
/usr/share/info/bash.info.gz
$ whereis -b bash // 仅查找 binary
bash: /usr/bin/bash /etc/bash.bashrc /etc/bash.bash_logout
$ whereis -m bash // 仅查找 manual
bash: /usr/share/man/man1/bash.1.gz /usr/share/info/bash.info.gz
find //也用于查找文件,但更为强大,支持正则,并且可将查找结果传递到其他命令。
$ find . -name PATTERN // 从当前目录查找符合 PATTERN 的文件
$ find /home -name PATTERN -exec ls -l {} \; // 从 /home 文件查找所有符合PATTERN的文件,
//并交由 ls 输出详细信息
tr //translate
cut
awk
sed //stream editor
wc // word count
解压命令 tar
tar主要用于创建归档文件,和解压归档文件,其本身是没有压缩功能的,但可以调用 gzip 、 bzip2 进行压缩处理。
参数解释:
-c 创建归档
-x 解压归档
-v 显示处理过程
-f 目标文件,其后必须紧跟 目标文件
-j 调用 bzip2 进行解压缩
-z 调用 gzip 进行解压缩
-t 列出归档中的文件
$ tar -cvf filename.tar . ### 将当前目录所有文件归档,但不压缩,
### 注意后面有个 ’.‘ ,不可省略,代表当前目录的意思
$ tar -xvf filename.tar ### 解压 filename.tar 到当前文件夹
$ tar -cvjf filename.tar.bz2 . ### 使用 bzip2 压缩
$ tar -xvjf filename.tar.bz2 ### 解压 filename.tar.bz2 到当前文件夹
$ tar -cvzf filename.tar.gz ### 使用 gzip 压缩
$ tar -xvzf filename.tar.gz ### 解压 filename.tar.gz 到当前文件夹
$ tar -tf filename ### 只查看 filename 归档中的文件,不解压
gcc时,不同的选项
- -E: 预处理,主要是进行宏展开等步骤,生成的文件为test.i:gcc -E test.c
- -S: 编译,生成汇编代码,生成的文件为test.s:gcc -S test.c
- -c: 汇编:生成机器码,生成的文件未test.o:gcc -c test.c
- -I 指定头文件所在目录位置
- -g 编译时添加调试文件,用于 gdb 调试
- -Wall 显示所有警告信息
- -D 向程序中“动态”注册宏定义
- -l 指定动态库库名
- -L 指定动态库路径
需要注意,-o本质上是一个重命名选项。无论有没有-o选项,最后都会执行链接的步骤。
当不使用-o选项时,执行命令gcc test.c,生成的是默认的a.out文件。但一般我们用-o重命名生成的文件,:使用命令gcc test.c -o test,生成可执行的test文件
gcc对于多个文件联合编译
gcc hello.c add.c sub.c div1.c -o a.out
正则表达式
重定向:将输出导入文件或从文件中读取数据
与管道相区别:管道用于将一个命令的标准输出重定向给下一个命令,并作为该命令的标准输入,管道可与重定向相结合使用。
有时我们希望将程序的输出信息保存到文件中, 方便以后查看. 例如你编译了一个程序myprog
, 你可以使用以下命令对myprog
进行反汇编, 并将反汇编的结果保存到output
文件中:
objdump -d myprog > output
>
是标准输出重定向符号, 可以将前一命令的输出重定向到文件output
中. 这样, 你就可以使用文本编辑工具查看output
了.
但你会发现, 使用了输出重定向之后, 屏幕上就不会显示myprog
输出的任何信息. 如果你希望输出到文件的同时也输出到屏幕上, 你可以使用tee
命令:
objdump -d myprog | tee output
使用输出重定向还能很方便地实现一些常用的功能, 例如
> empty # 创建一个名为empty的空文件
cat old_file > new_file # 将文件old_file复制一份, 新文件名为new_file
如果myprog
需要从键盘上读入大量数据(例如一个图的拓扑结构), 当你需要反复对myprog
进行测试的时候, 你需要多次键入大量相同的数据. 为了避免这种无意义的重复键入, 你可以使用以下命令:
./myprog < data
<
是标准输入重定向符号, 可以将前一命令的输入重定向到文件data
中. 这样, 你只需要将myprog
读入的数据一次性输入到文件data
中, myprog
就会从文件data
中读入数据, 节省了大量的时间.
下面给出了一个综合使用重定向的例子:
time ./myprog < data | tee output
这个命令在运行myprog
的同时, 指定其从文件data
中读入数据, 并将其输出信息打印到屏幕和文件output
中. time
工具记录了这一过程所消耗的时间, 最后你会在屏幕上看到myprog
运行所需要的时间. 如果你只关心myprog
的运行时间, 你可以使用以下命令将myprog
的输出过滤掉:
time ./myprog < data > /dev/null
/dev/null
是一个特殊的文件, 任何试图输出到它的信息都会被丢弃, 你能想到这是怎么实现的吗? 总之, 上面的命令将myprog
的输出过滤掉, 保留了time
的计时结果, 方便又整洁.
Tmux
man的用法
man -a:搜索并打开所有man中同名帮助,例如 man passwd ,你首先会进入一个PASSWD(1) section用户命令类的帮助手册,你再按q键退出当前正在显示的帮助手册,就会进入PASSWD(5) section文件格式类的帮助手册。
man -aw:显示所有手册文件的路径。例如man -aw passwd
/usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz
man -M:指定手册文件的搜索路径,有的时候我们自己安装的软件是带有自己的帮助文件的,通常不在我们的MANPATH 里面,那么我们就可以手动指定man搜索的文件路径。如 man -M /home/mysql/man mysql 显示的就是你安装的mysql的帮助,而不是系统默认的旧版mysql的帮助。
man -k:根据关键字搜索联机帮助,是一种模糊搜索。例如要查找"passwd"相关的信息,使用man -k passwd会找到很多和passwd相关的帮助页。
man -f:关键字精确搜索,与-k不同,它只搜索与关键字完全匹配的帮助页
在进行pa0时,make menuconfig遇到的问题
缺少了几个安装包,讲义中为给出。执行下面三个命令即可
sudo apt-get install ncurses-dev
sudo apt-get install flex
sudo apt-get install bison
apt命令
apt-get
update | 更新软件包列表 |
upgrade | 升级系统中的所有软件包 |
install | 安装软件包 |
remove | 卸载软件包 |
autoremove | 仅删除不需要再次下载的软件包 |
purge | 彻底删除软件包(包括配置文件) |
source | 下载源代码 |
build-dep | 自动下载安装编译某个软件所需要的软件包 |
dist-upgrade | 升级整个发行版 |
dselect-upgrade | 安装dselect的选择进行升级 |
clean | 删除本地缓存的所有升级包 |
autoclean | 删除本地缓存中无用的软件包 |
check | 检查是否存在有问题的依赖关系 |
其他
apt-cache search
apt_cache show
查看软件包的版本信息
dkpg -l name_of_pkg
关于换源
sudo vi /etc/apt/sources.list
makefile
跟我一起写 Makefile(一)_陈皓专栏 【空谷幽兰,心如皓月】-CSDN博客_makefile
Makefile中的$@, $^, $< , $?, $%, $+, $*_Jeffrey0000的专栏-CSDN博客
“$”:主要扩展打开makefile中定义的变量
反斜杠 \ 用于makefile中语句的换行
@:使跟在其后的命令不在屏幕上显示出来
$@ 表示目标文件
$^ 表示所有的依赖文件
$< 表示第一个依赖文件
$? 表示比目标还要新的依赖文件列表
makefile中“:= ”与 “=” 的区别
“=”
“=”是最普通的等号,然而在Makefile中确实最容易搞错的赋值等号,使用”=”进行赋值,变量的值是整个makefile中最后被指定的值。不太容易理解,举个例子如下:
VIR_A = A
VIR_B = $(VIR_A) B
VIR_A = AA
经过上面的赋值后,最后VIR_B的值是AA B,而不是A B。在make时,会把整个makefile展开,拉通决定变量的值
“:=”
相比于前面“最普通”的”=”,”:=”就容易理解多了。”:=”就表示直接赋值,赋予当前位置的值。同样举个例子说明
VIR_A := A
VIR_B := $(VIR_A) B
VIR_A := AA
最后变量VIR_B的值是A B,即根据当前位置进行赋值。因此相比于”=”,”:=”才是真正意义上的直接赋值。
make命令具有时间戳功能,如果编译需要的依赖文件的足后修改时间早于已存在的目标文件的最后修改时间,此时再次make的话,系统会选择不重新make。如果要强制make的话,可以用
make -B // always make
除此之外,make还有一个指令,只将要被执行的指令的打印出来,但不去执行它 :
make -n // just print
将两者结合,可以将所有要被执行的指令打印出来:
make -nB
grep与find的组合
grep -n main $(find . -name "*.c")
//在当前文件夹下所有.c的文件中寻找含关键字main的行,-n表示显示结果的同时标注结果的列号。
LINUX可用于管道操作的命令
管道命令:|
command1 | command2 | command3
注:管道命令必须能够接受来自前一个命令的数据成为standard input继续处理。
cut 将一段信息的某一段切出来,处理的信息是以行为单位。
cut -d '分割字符' -f fields cut -c 字符范围
参数:
-d : 后面接分隔符,与-f一起使用;
-f : 依据-d的分隔符将一段信息切割成为数段,用-f取出第几段的意思;
-c : 以字符(characters)的单位取出固定字符区间;
echo $PATH | cut -d ':' -f 3-5
//将path的值按照':'进行分割,后取出第3到5个值
export | cut -c 12-
//对export的输出进行切分,每行输出从第12个字符往后的内容
grep 分析一行信息,如果有匹配的,就将该行拿出来。
grep [-acinv] [--color=auto] '查找字符串' filename
参数:
-a : 将binary文件以text文件的方式查找数据;
-c : 计算找到’查找字符串‘的次数;
-i : 忽略大小写的不同;
-n : 带行号;
-v : 反向选择,显示没有‘查找字符串’的行;
--color=auto : 可以将找到查找的关键字部分加上颜色显示
export | grep -in --color=auto 'bin'
//列出export输出中带有bin的行,并给bin加上颜色,不区分大小写,带有行号。
sort 可以依据不同的数据类型进行排序。
sort [-fbMnrtuk] [file or stdin]
参数:
-f : 忽略大小写
-b : 忽略最前面的空格符
-M : 以月份的名字来排序,如 JAN, DEC等
-n : 使用“数字”进行排序(默认是以文字类型来排序的)
-r : 反向排序
-u : uniq,相同的数据,仅出现一行代表
-t : 分隔符,默认是[Tab]来分割
-k : 用哪个filed来进行排序,与-t相关
cat /etc/passwd | sort -t ':' -k 3 -n
//根据 passwd中每行,按':'分隔符进行分隔后,按照第3个字段使用纯数字的方式进行排序。
uniq 重复的行只显示一个
uniq [-ic]
参数:
-i : 忽略大小写
-c : 进行计数
last | cut -d ' ' -f1 | sort | uniq -c
//列出登录者名字,并进行排序,进行统一处理,并计数。
wc 输出信息的整体数据
wc [-lwm]
参数:
-l : 仅列出行
-w : 仅列出多少字(英文单字)
-m : 多少字符
cat /etc/man.config | wc
//输出三个数字,分表代表行,字数,字符数
tee 双重定向,存到文件/设备的同时,输出到屏幕以便继续处理。
tee [-a] file
参数:
[-a] : 以累加(append)的方式,输出到file中。
ls -l / | tee -a file.list | more
//把文件目录输出到file.list中,同时用more将其输出到屏幕。
tr 删除一段信息中的文字,或者进行文字信息的转换。
tr [-ds] XXX ...
参数:
-d : 删除信息中XXX这个字符串
-s : 替换掉重复的字符
last | tr '[a-z]' '[A-Z]'
//将last输出的信息中所有的小写字母变成大写字母
col 对特殊字符进行处理
col [-xb]
参数:
-x : 将tab键转换成对等的空格键
-b : 在文字内有反斜杠(/)时,仅保留反斜杠最后接的那个字符
cat /etc/man.config | col -x | cat -A | more
//将/etc/man.config内容中的[tab]转成空白,并输出。
join 将两个文件当中有相同数据的那一行加在一起。
join [-ti12] file1 file2
参数:
-t : join默认以空格符分隔数据,并且对比“第一个字段”的数据;如果两个文件相同,则将两条数据连成一行,且第一个字段放在第一个。
-i : 忽略大小写
-1 : (数字1),代表第一个文件要用哪个字段进行比较
-2 : 代表第二个文件要用哪个字段进行比较
join -t ':' -1 4 /etc/passwd -2 3 /etc/group
//用分隔符':'进行分隔,第一个文件用第4个字段,第二个文件用第3个字段,进行分析。
paste 将两个文件贴在一起,中间以[tab]键隔开。
paste [-d] file1 file2
参数:
-d : 后面可以接分隔符,默认是以[tab]进行分隔
- : 如果file部分写成-, 表示来自standard input的数据的意思
cat /etc/group|paste /etc/passwd /etc/shadow - |head -n 3
//先将/etc/group读出,然后与/etc/passwd和/etc/shadow合并的内容粘贴在一起,且仅取出前三行。
expand 将[tab]按键转成空格键
expand [-t] file
参数:
-t : 后面可以接数字,代表一个tab用几个空格表示
xargs 读入stdin的数据并且以空格符或断行符进行分辨,将stdin的数据分隔为arguments。
xargs [-0epn] command
参数:
-0 : 如果输入的stdin含有特殊字符,如`,\,空格键等,这个参数可以将它还原成一般字符。
-e : 是EOF(end of file)的意思,后面可以接一个字符串,当xargs分析到这个字符串时,就停止继续工作。
-p : 在执行每个命令的参数时,都会询问用户的意见
-n : 后面接次数
cut -d ':' -f1 /etc/passwd | xargs -p -e'lp' finger
//分析到lp这个字符串时,后面的其它stdin的内容就被xargs舍弃掉了。
举个例子
如果你想统计一个文件夹下java代码的文件数量
find [folderPath] -name "*.java" | wc -l
那如果我想查询所有java代码的行数呢?
可以用xargs,因为wc -l filename可以查询单个文件的行数
find [folerPath] -name "*.java" | xargs wc -l
如果要去掉空行
find [folderPath] -name "*.java" |xargs cat| grep -v ^$|wc -l
管道与xargs的区别
辨析:标注输入与参数输入
linux命令可以从两个地方读取要处理的内容,一个是通过命令行参数,一个是标准输入。拿cat来举例,cat同时接受参数输入和标准输入。
//标准输入
swp$ cat //输入cat 回车后,会等待来自键盘的输入并显示在屏幕上,ctrl+d用于退出
swp
swp
11
11
//参数输入
swp$ cat swp123 //输入cat swp123 回车后, 会寻找名为swp123的文件并打印在屏幕上
cat: swp123: 没有那个文件或目录
由上面可以看出,标准输入与参数输入的区别就在于,回车键按下的先后顺序不同。一个是来自键盘的输入,一个是来自命令行的输入。
- 管道符 将 “|” 之前的命令标准输出,作为之后命令的标准输入。
- xargs 将上一命令的标准输出,作为后面命令的参数args。
echo "--help"|cat
echo "--help"|xargs cat
管道符后不加xargs,相当于先将管道符后面的命令cat回车执行一下,再从键盘里输入管道符前面命令执行的结果内容
加上xargs 相当于在cat 后加上管道符前面命令执行的结果内容,再回车
至此,可以对xargs给出一个严谨的定义:xargs命令可以通过管道接受字符串,并将接收到的字符串通过空格分割成许多参数(默认情况下是通过空格分割) 然后将参数传递给其后面的命令,作为后面命令的命令行参数
参考:linux xargs与管道的区别_whatday的专栏-CSDN博客_linux xargs
KILL命令
kill 的作用是向一个进程发送指定信号
kill -l 列出所有信号
linuxy@linuxy:~$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
kill -l ''信号名字/信号编号'' 得到指定信号的数值或者名字
linuxy@linuxy:~$ kill -l 9
KILL
linuxy@linuxy:~$ kill -l KILL
9
linuxy@linuxy:~$ kill -l SIGKILL
9
linuxy@linuxy:~$
常用信号
HUP 1 终端断线
INT 2 中断(同 Ctrl + C)
QUIT 3 退出(同 Ctrl + \)
TERM 15 终止
KILL 9 强制终止
CONT 18 继续(与STOP相反, fg/bg命令)
STOP 19 暂停(同 Ctrl + Z)
kill -''信号名字/信号编号'' 进程号
[root@localhost test6]# ps -ef|grep vim
root 3268 2884 0 16:21 pts/1 00:00:00 vim install.log
root 3370 2822 0 16:21 pts/0 00:00:00 grep vim
[root@localhost test6]# kill –9 3268
[root@localhost test6]# kill –SIGKILL 3268