说明

本文为Linux应用技术的学习笔记整理自陈真老师的课程,课程链接在文章结尾。文章可供自查常见的linux命令以及了解系统引导、vi编辑器、shell程序设计、常用开发工具等内容。

系统引导

查看LinuxCPU信息:

cat /proc/cpuinfo

查看当前内存:

free

cat /proc/meminfo

硬盘:

读写以扇区为单位,512byte

分区以柱面为最小单位

每个磁道扇区数相同,扇区数是格式化时确定的

容量=磁头数(head)* 磁道(柱面数、cylinder)* 每道扇区数(sector)*每扇区字节数(512b)

通常磁头数=盘片数量N * 2-2

磁盘分区:

分区机制:MBR使用BIOS的设备,GPT使用UEFI的设备

分区信息:主要启动记录区(MBR,安装启动管理程序,446b),磁盘分区表(记录整颗硬盘的分区状态,64b),启动标志(判断是否为启动设备,2b),共512b

MBR流程:BIOS加电自检、MBR读取第一个可启动装置的第一个扇区内的主要启动记录区块,启动管理程序(boot loader),加载核心文件

系统启动过程:内核引导,运行init,系统初始化,建立终端,用户登录系统

主分区+拓展分区<=4,拓展分区<=1,但可以有多个逻辑分区 拓展分区是56789

IDE硬盘最多有59个逻辑分割,SATA硬盘最多有11个逻辑分割

进入分区系统:

fdisk /dev/sda ,(a是sata插槽上第一块硬盘,dev/sdb是第二个插槽上的文件名,以此类推,u盘插入后才显示)

p打印当前分区信息

紧接着输入n创建分区,再输入创建p主分区,e创建扩展分区,依次输入创建1-4中的数字指定创建哪个分区,第一个扇区,最后一个扇区(可以输入+2g这样的)

w把分区表的信息写到磁盘上再退出,q不保存就退出。

查看当前分区情况:

fdisk -l

建立文件系统(格式化):

文件系统格式:FAT32 NTFS ext2 ext4等

命令:mkfs -t ext4 /dev/sdb5

检查文件系统的磁盘空间占用情况:

df(挂载后才显示)

挂载:

先要到一个地方(如/mnt/E)创建一个文件夹,然后将分区挂载在对应的硬盘中

创建文件夹:mkdir /mnt/E

mount挂载:mount /dev/sdb5 mnt/E

永久挂载:vim /etc/fstab

/dev/sdb5 /mnt/E ext4 defaults 0 0

取消挂载:umount /mnt/E

常用命令

shell终端进入和退出:

进入:打开终端、ctrl+alt+t

退出:exit、ctrl+d

用户切换:

#root:sudo su root、su - root

系统安装后设置root用户密码:sudo passwd root

$普通用户:su - username 、exit

系统支持的Shell:

查看所有shell:cat /etc/shells

查看当前合法(默认)shell:echo $SHELL

每一个命令实际上都是一段程序,你也可以自定义命令

标准输出:

echo

类似于其他语言的print

(>表示命令没有输入完成,可以继续输入)

xx命令帮助

whatis xx

外置命令帮助文档:

man 命令名

查看内置命令帮助文档:

help 命令名

查看是外部命令还是内置命令:

type 命令名

内置命令常驻内存,执行效率高

外部命令是系统的软件功能,需要使用时才从硬盘读入内存

补全命令:

写一个命令写一半,tab键可以自动补全命令,连续按两下tab可以补全所有以此命令开头的命令,不能补全参数

历史命令:

history查看所有执行过的命令

echo $HISTSIZE可查看最大的历史命令

↑↓键查看历史命令

命令行通配符:

!! 重复上一个命令

!字符 重复上一个以“字符”开头的命令

!num 按照历史记录的序号执行命令

!-n 重复n个命令之前的那个命令

Bash操作快捷方式:

终止当前命令:ctrl+c

暂停当前命令:ctrl+z

暂停屏幕输出:ctrl+s

恢复屏幕的输出:ctrl+q

列出当前使用系统的用户:

w、who、whoami(命令字越多,输出的内容越简单)

输出时间表示:

date

date +"%Y-%m-%d"(输出年月日)

date +"%Y-%m-%d %H:%M:%S"(输出年月日分时秒)

date -d "+1 day" +"%Y-%m-%d"(输出前一天的年月日,+1day处可任意更换为month、year、-1等)

date +“%s” (自1970.1.1 0点以来的秒数)

传说中的时间戳:1234567890 2009.2.13 11:31:30pm

日历:

cal

cal 5 2019(2019.5的日历)

cal -y 2018 (2018的日历)

cal -j (自一月一日的天数)

清屏:

clear、ctrl+l

修改用户密码:

passwd

文件系统:

文件的成分:索引节点(inode)+数据(block)

查看inode:stat 文件名

inode的内容:文件的字节数、文件数据block的位置、文件拥有者的UserId,文件的GroupID问价的读写执行权限、链接数(有多少文件名指向这个文件的inode)、时间戳(ctime inode上一次变动是按、mtime文件内容上一次变动时间、atime上次打开时间)

block的内容:存储文件的数据数据,8个sector组成一个block区块中一个文件占用一个inode,同时记录此文件所在的block号,若文件太大可能会占用多个数据库

读取文件流程:找到文件对应的inode号,通过inode号码查找inode表,获取inode信息,找到文件数据所在的block,读出数据

block数据的读取和文件系统有关

文件类型:

ls -l 可以查看各个文件的文件类型

普通文件(文本、数据、二进制文件) -

目录(特殊文件,利用它可构成文件系统的分层树状结构) d

符号链接(特殊文件,提供对其他文件的惨遭) l

块设备(特殊文件,用来标记各个设备驱动器,伪文件) b

字符设备(同上) c

链接文件:

硬链接:

在本目录或其他目录增加目标文件的一个目录,本质上使用目标文件的inode进行创建连接

ln创建硬链接,增加连接数,rm减少连接数,为0时候才会被删除

ln 源文件 [目标文件]

软链接(符号连接):

将一个路径名链接到一个文件(类似快捷方式),ln -s 源文件(绝对路径)[目标文件]

连接文件的作用:

节省硬盘空间、文件安全考虑、防止文件误删、编写文件同步

显示文件内容:

cat 文件路径名

-b 从1开始对所有非空输出行编号

-n 从1开始对所有输出行编号

-s 将多个相邻空行合并为一个空行

tac 文件目录 倒着显示内容

逐行显示:

more 文件路径名

按q退出

-num 一屏显示多少行

-d 在底部显示更加友好的提示

-s 将多个相邻空行合并为一个空行

+num 从行号num开始

前后浏览文件:

less 文件路径名

按q退出

显示文件的头几行:

head 文件路径名

默认显示头十行

显示文件的最后几行:

tail 文件路径名

默认显示自耦鸡皮十行

新建文件/修改时间:

touch 文件名

-a 仅改变指定文件的存取时间

-c 不创建任何文件

-m 仅改变指定文件的修改时间

-t STAMP 使用STAMP指定的时间标签,格式:YYYYMMDDhhmm

查找含某字符对应的行:

grep ’查找字符串‘ 文件名

排序:

sort 文件列表

可以是对很多文件进行排序,也可以对文件中的内容进行排序

-u 对排序的结果去重

比较相邻的行并去除重复的行:

uniq 文件名

-c 显示该行出现的次数

-d 只显示重复的行

-u 只显示不重复的行

比较两个排好序的文件:

comm file1 file2

要先用sort排序

第一列是只在第一个文件出现的字符

第二列是只在第二个文件出现的字符

第三列是共同出现的字符

-123 分别表示不显示comm输出中的一二三列

比较两个文件并找出他们的不同

diff file1 file2

输出如何改变第一个文件使他和第二个文件匹配

例如:

4c4 4表示第一个文件的第四行有变化,c表示change,4表示变动后变成第二个文件的第四行;

<a表示要删除第一个文件的此行(第四行)内容,---是分隔符,>b表示第一个文件增加了此行,b表示此行的内容

复制:

如果复制的对象是目录,不能直接复制,要加上 -r参数

将/etc/ 目录下的所有内容复制到/tmp:cp -r /etc/ /tmp

将/var/log/wtmp复制到/tmp下:cp /var/log/wtmp /tmp

-开头是选项,-f是强制的意思,是可选的

正常执行会返回0,表示执行成功

删除文件:

rm 文件路径名

删除目录需要加入-r选项

文件移动/改名:

对文件或者目录改名,或者从一个目录移到另一个目录中

mv path1 path2

文件内容统计:

wc file1

-c 统计字节数

-l 统计行数

-w 统计字数

显示当前目录的树状结构:

tree -L

目录管理:

bin 普通用户可执行指令

boot 开机引导目录

dev 设备目录

etc 各种配置文件目录

lib/lib64 开机时常用的动态链接库

media 可以出设备挂载目录

mnt 用户临时挂载其他的文件系统

opt 第三方软件安装目录

proc 虚拟文件系统

root 系统管理员主目录

run 系统运行时所需的目录

sbin 只有root才能运行的管理指令

snap 乌班图全新软件包管理方式

srv 服务启动后需要访问的数据目录

sys 根proc一样的虚拟文件系统

tmp 存放临时文件目录

usr 应用程序放置目录

var 存放系统执行过程经常改变的文件

查看当前工作目录:

pwd

切换目录:

cd

上一级目录..

当前目录.

当前用户家目录~

创建目录:

mkdir dirname

删除目录:

rmdir dirname

-p 递归删除目录(同时删除空的父目录)

当前目录文件:

ls pathname

如果没有这个文件夹 会自动创建

当前目录下所有可见文件的详细属性:ls -l

-a显示目录下所有的子目录和文件

-i 显示文件的inode号和对应的文件名

-ail 显示以上所有信息

显示当前用户的id、组等用户权限信息

id

权限管理目录:

/etc/passwd 储存用户信息

/etc/shadow 用户密码

/etc/group 用户的组信息

同一个用户可以属于多个组

用户管理:

id从1000开始,每创建一个id+1

创建用户:useradd 用户名 或adduser 用户名(多了逐步提示)

修改用户信息:usermod 用户名

-d 家目录

-s 登录shell

-u userID

-g 所属组

-G 附属组

删除用户:userdel 用户名

-r可以将用户及其家目录删除

组管理:

创建组:groupadd 组名

修改组:groupmod 组名

-n 修改组名

-g 修改组id

删除组:groupdel 组名

查看当前用户所属组:groups

权限管理:

读(r)、写(w)、可执行或查找(x)

文件:可读取文件内容(r),可修改文件内容(w),可作为命令执行(x)

文件夹:可列出目录内容(r),可在目录中创建删除文件(w),可访问目录内容(x)

ls -l 文件/目录名 查看当前权限

-rwxrwxrwx的解释:第一个-为分隔符,第一组rwx说明当前用户对于这个文件/目录有读写执行权限,第二组表示当前组的权限,第三组为其他组的权限,若没有权限则显示-

修改权限:

chmod key 文件/目录名

key:[操作对象] [操作符号] [权限]

操作对象(可组合):u(文件主) g(当前组) o(其他组) a(所有用户)

操作符号:+ - =

权限:r w x

chmode mode 文件/目录名

mode是由三位八进制数字组成的第一位表示文件主权限,第二位表示组用户权限,第三位表示其他用户权限

例如rexr-xr--使用二进制表示111101100 转为三位八进制为754

限制新建文件权限的掩码:

umask mod

例如:umask u=, g=w, o=rwx

用户所能拥有的最大权限为777,对于文件,用户所能拥有的最大权限是目录的最大权限-执行权限,即666

ubuntu默认的umask是0022

创建文件默认权限644

创建目录默认权限755

改变用户组和文件主:

chgrp [-R] 组名 文件名

改变指定文件所属的用户组

chrown [-R] 用户或组 文件名

改变某个文件或目录的所有者

-R 递归的改变其下面的子文件和目录的用户组

查看进程状态:

ps

结束进程:

kill 进程号

休眠:

sleep 时间(s、m、h)

后台命令:

命令 &

压缩文件:

gzip 文件名

压缩后扩展为.gz,原来文件的会删除

zip 压缩有文件名.zip 压缩的文件

压缩后扩展名为.zip,原来的文件会留着

tar -cxf all.tar.gz *.c

将所有.c文件打成一个tar包,并将其用gzip压缩,生成一个gzip压缩过的包,报名为all.tar.gz

解压:

gzip -dv 文件名.gz

unzip 文件名.zip

tar -xzf all.tar.gz (这条命令是将上面tar命令产生的包解压)

vi编辑器

打开/新建文件:

vi 文件名

打开指定行数:

vi 文件名 +行数

定位到文件末尾:

vi 文件名 +

异常退出处理:

打开文件后 按下字母d删除交换文件(先要关闭输入法)

工作模式:

img

插入模式:

在光标之前插入:i

在光标行首插入:I

在光标后插入:a

在钢表行位插入:A

在光标所在行的下面插入一行:o

在光标所在行的上面插入一行:O

撤销:u

撤销到编辑之前的状态:U

重做:ctrl+r 或者.

命令模式:

删除光标所在的字符:x

删除光标前面的那个字符:X

删除光标所在的整行:dd

删除光标开始到行尾:D

从光标位置开始删到光标移动限定的文本对象的末尾:d <光标移动命令>

检索:/要检索的字符串

ex转义模式(末行模式):

保存并退出:wq

把修改写回指定文件:w 文件名

如果修改过,保存当前文件然后退出:ZZ 或者 x

强行退出vi:q!

显示行号:set nu

跳转到指定行号:20 <回车>

移动光标:

hjkl分别是左下上右

Shell程序设计

简单介绍:

Shell是linux上的第一层软件,是命令解释程序,也是一种高级程序设计语言。

有以下特点:

  • 组合新命令
  • 直接使用shell的内置命令
  • 结构化的程序模块
  • 可配置的环境
  • 提供了文件名拓展字符
  • 灵活的使用了数据流
  • 在后台执行命令
  • 高级命令语言

最简单的shell程序:

$ cat ex1
date
pwd
cd ..
pwd
# 通过./ex1.sh执行 
# ./表示当前目录
$ cat ex2
# 下面一行宣告这个script使用的shell名称
#!/bin/bash
if test $# = 0
then ls .
else
    for i
    do
    ls -l $i | frep '^d'
    done
fi

执行shell脚本的方式:

./ 脚本名(要先使用chmod a+x 脚本名给他加上执行权限)

bash <脚本名(不能带参数)

bash 脚本名 [参数]

脚本名 (需要先将该目录加入环境变量并加入权限)

PATH=$PATH:.  
PATH=$PATH:`pwd`
#以上都是临时的,若想永久有效则为
export PATH="$PATH:目录"
#或者将脚本文件放到环境变量对于的文件夹中也可以全局有效

别名:

定义别名:alias 别名='别名代表的命令'

取消别名:

unalias name

将所有别名都从别名表中删除:unalias -a

查看别名表:alias

通配符(正则表达式):

*通配符匹配任意一个或多个字符

?通配符匹配一个任意字符

[list]匹配list中任意单个字符

![list]匹配不在list中的单个字符

双引号:

由双引号括起来的字符除了$ (全局变量)`(命令) \(转义字符)外均作为普通字符看待

单引号:

括起来的字符都作为普通字符看待

echo 'helloworld'

倒引号:

``内的字符视为命令

例如 echo `pwd`

输入重定向:

命令<文件名

输入文件名的内容给命令

输出重定向:

命令>文件名

例如man > abc.txt 就是把man的内容输出到abc.txt中

输入输出重定向:

输入和输出重定向可以连在一起使用例如:

wc -l < infile > outfile(将infile的行数输出到outfile中)

输出附加重定向:

<<

管道线:

|左边的输出作为|右边的输入并输出到outfile中

例子:

cat infile | wc -l > outfile

命令执行操作符:

顺序执行:;

逻辑与:命令1&&命令2,先执行命令1执行成功才执行命令2,否则不执行命令2

逻辑或:命令1||命令2,先执行命令1执行不成功则执行命令2,否则不执行命令2

命令组成:

{}中的全部命令视为语法上的一条命令,注意{后面应该有一个空格,}之前应有一个分号

()中的全部命令视为语法上的一条命令,没有后面的要求

区别:{}内只是再本shell内执行命令表,不产生新的进程,()内是在新的shell内执行,要建立新的子进程

用户定义的变量:

变量定义并赋值:变量名=字符串(等号前后没有空格)

引用变量值:在变量前面加入$

数组:

name=(value1 ... valuen),下标从0开始,不支持多维数组,初始化不需要定义数组大小

例如 a=(1 2 3 4)

可通过a[3]=2赋值

显式声明一个数组 declare -a 数组名

读取数组:

读取数组中的第i个元素${name[i]}

如果不指定下标则访问下标0的元素${name}

或者@当做下标则表示数组中的所有非空元素${name[@]} ${name[]}

变量名前加#表示数组长度 ${#name}

第i个元素的字符个数${#name[i]}

已经赋值的元素个数${#name[@]} ${#name[*]}

输入命令:

read 变量1 变量2

若变量个数少于数据个数则最后一个变量被赋予剩余的所有数据

若变量个数多余数据个数则没有数据的变量取空串

位置参数:

命令行实参与位置参数的对应关系如下:

命令行: exam1 m1 m2 m3 m4

位置参数:$0 $1 $2 $3 $4

位置参数不能通过赋值的方式直接赋值,通过命令行上对应的位置的实参传值

通过set命令赋值$1 到$n的位置参数(不能通过set赋值$0)

通过shift右移位置参数(实参左移一位),shift n为位置参数右移n位

命令行: exam1 m1 m2 m3 m4

原位置参数:$0 $1 $2 $3 $4

新位置参数:$0 $1 $2 $3 $4

预先定义的特殊变量:

$# 命令行上参数的个数(不包含脚本名本身)

$? 上一条命令执行后的返回值

$ $ 当前进程的进程号

$* 上一个后台命令对应的进程号

@ 与*相同

常用的环境变量:

env可查看当前的所有环境变量

HOME 用户主目录的券路径名

LOGNAME 注册名,由linux自动设置

PATH shell从中查找命令的目录列表

PWD 当前工作目录的路径

SHELL 当前使用的shell

TERM 终端类型

使用环境变量:echo $环境变量名

删除环境变量:unset 环境变量名

环境文件:

bash的环境文件包括

.bash_profile文件(设置了环境变量和文件掩码umask)

bashrc文件(每次注册bash时便会执行它,用来设置别名)

bash_logout文件(退出注册时候运行)等

算数运算:

使用let "表达式"命令

let "j=i*6+2"

等价于

((j=i*6+2))

if语句:

if 测试条件1
then 命令1
elif 测试条件2
then 命令2
else 命令3
fi

其中 if、then、else、fi是关键字,else 、elif可以缺省

测试条件可以使用一条命令执行成功与否作为判断,成果返回0,测试条件为真,否则返回1,测试条件为假

测试条件:

test -f "$1"

[ -f "$1" ] 注意[]中左右都要有空格

[[-f "$1"]]

文件测试条件:

test [参数] 文件名

-r 文件存在并是用户可读,为真,下同

-w 文件存在并是用户可写

-x 文件存在并是用户可执行

-f 文件存在并是普通文件

-d 文件存在并是目录文件

-b 文件存在并是块设备文件

-c 文件存在并是字符设备文件

-s 文件存在并文件长度大于0

字符串测试条件:

-z s1 如果s1长度为0,为真,下同

-n s1 如果s1长度>0

s1 如果s1不是空串

s1 = s2 如果s1等于s2,=可用==代替,=前后要有空格

s1 != s2 如果s1不等于s2

s1 < s2 如果字典顺序s1在s2前

s1> s2 如果字典顺序s1在s2后

数值测试条件:

n1 -eq n2 如果整数n1等于n2,为真,下同

n1 -ne n2 如果整数n1不等于n2

n1 -lt n2 如果n1<n2

n1 -le n2 如果n1<=n2

n1 -gt n2 如果n1>n2

n1 -ge n2 如果n1>=n2

逻辑测试条件:

! 逻辑非

-a 逻辑与

-o 逻辑或

() 整体

case语句:

case 字符串 in
    命令1)
        命令2
        ;;
    命令3)
        命令4
        ;;
    命令5)
        命令6
        ;;
    #……可以无限往下面写
    *)
        命令n
esac

while语句:

while 测试条件
do 
命令表
done

测试条件除了使用test命令或等价的方括号外,还可以是一组命令,根据最后一个命令的退出值决定知否进入循环体执行

unitil语句:

until 测试条件
do
命令表
done

与while像素但是测试条件不同,当测试条件为假时,才进入循环体直到测试条件为真

for语句:

for 变量 in 值表(可以是数组之类的);
    do 命令表;
done
for 变量 in 文件正则表达式
do
    命令表
done
for i in $* #取全部位置参数
do
    命令表
done
#或者
for i
do
    命令表
done

break:

break命令使程序从循环体中退出来

break n n表示循环层数,不写则为默认1

continue:

跳过循环体中它之后的语句,回到本层循环的开头,进行下一次循环

continue n n表示循环层数,不写则为默认1

exit:

退出正在执行的shell脚本

exit [n]

函数:

[function] 函数名()
{
	命令表
}

函数应先定义后使用,调用时,直接利用函数名。

shell脚本与函数建的参数传递可利用位置参数和变量直接传递。

函数中最后一个命令执行之后就退出被调函数,也可以利用return命令退出函数,语法格式为return [n]

常见错误:

  • 没有在第一行加上#!/bin/bash,导致不能直接在其他shell下运行bash脚本
  • 在PATH环境变量中没有包括“.”(当前工作目录),解决办法是设置PATH:PATH=$PATH:.
  • 脚本文件与已存在命令的名字相同导致脚本无法运行。

常用开发工具

gcc编译系统

编译执行过程:

编译器读取源代码->编译生成可执行文件->让操作系统加载运行这个可执行文件->运行的结果出现在屏幕上

解释执行过程:

解释器读取源代码解释执行->程序的结果出现在屏幕上

文件后缀:

.c c源程序

.i 预处理后的c源程序

.ii 预处理后的c++源程序

.m objective-c源文件

.mi 预处理后的objective-c源程序

.h 头文件

.cpp c++源文件

.F .fPP .FPP fortran源文件

.s 汇编程序文件

.S 必须预处理的汇编程序文件

.o 目标文件

.a 静态链接库

.ao 动态链接库

c语言编译过程:

  1. 源文件
  2. 预处理(展开头文件)后得到.i预处理后文件
  3. 通过编译程序得到.s汇编代码
  4. 通过汇编程序得到.o目标文件
  5. 通过库函数文件.a .so通过链接程序得到可执行文件.out

命令行编译:

gcc -E hello.c -o hello.i #预处理
gcc -S hello.i -o hello.s #编译为汇编语言代码
gcc -c hello.s -o hello.o #生成目标语言
gcc hello.o -o hello      #生成可执行程序

gdb调试工具

程序中的错误分类:

编译错误(语法错误),运行错误(例如复数开平方、除0错误),逻辑错误(程序设计错误)

启动gdb和查看内部命令:

需要先编译源文件,编译时使用-g选项:

gcc -g prog.c -o prog(针对prog.c源文件)

gcc -g program.cpp -o program(针对program.cpp源文件)

启动gdb的方式:

直接使用shell命令gdb

以一个可执行文件作为gdb的参数

同时以可执行程序和core文件作为gdb的参数

指定以一个进程号PID作为gdb的第二个餐宿

模式搜索:

向前搜索:forward-search 搜索内容

向后搜索:reverse-search 搜索内容

直接搜索:search 搜索内容

断点:

设置断点:

break 行数/函数/file:函数

显示断点:

info breakpoints [num]

info break [num]

单步跟踪:

step [N]跳进函数

next [N]函数当做一条命令

连续执行:

continue、c、fg

函数调用:

call 函数名

程序维护工具make

make工作过程:

  1. 依次读入各makefile文件
  2. 初始化文件中的变量
  3. 推到隐式规则,并分析所有规则
  4. 为所有的目标文件创建依赖关系链
  5. 根据依赖关系和时间数据,确定哪些目标文件要重新生成
  6. 执行响应的生产命令

Makefile文件:

建立文件之间的依赖关系

例如:hello文件依赖于hello.o依赖于hello.c

hello:hello.o #若依赖多个文件,在这继续往下写他依赖的文件
	@echo "gcc hello.o -o hello"  #输出
	gcc hello.o -o hello
hello.o:hello.c
	@echo "gcc -c hello.c -o hello.o"
	gcc -c hello.c -o hello.o
clean: #使用make clean执行
	@echo "Clean Project"
	-rm hello *.o
	@echo "Clean Complete"

推荐阅读:

https://blog.csdn.net/chengqiuming/article/details/88376143

https://www.bilibili.com/video/BV12T4y1P7vw?share_source=copy_web

课程链接

Linux应用技术 陈真 燕山大学