Linux Basic Knowledge
Terminal 快捷键
历史命令:
- Ctrl P : 上一条命令,可以一直按表示一直往前翻
- Ctrl N : 下一条命令
- Ctrl R,再按历史命令中出现过的字符串:按字符串寻找历史命令
命令行编辑:
- Ctrl A : 移动光标到命令行首
- Ctrl E : 移动光标到命令行尾
- Ctrl B : 光标后退
- Ctrl F : 光标前进
- Ctrl W : 删除光标前的单词
- Ctrl K :删除光标之后所有字符
- Ctrl U : 清空当前键入的命令
用户及用户组相关
|
|
用户
useradd
: 创建用户(adduser
是其提升易用性的封装命令)usermod
: 修改用户userdel
: 删除用户(deluser
是其提升易用性的封装命令)
使用 id
命令可以查看用户所属组
用户组
groupadd
: 创建组groupmod
: 修改组groupdel
: 删除组
/etc/group
文件存储了各个组包含的用户
管理员权限
We discuss three combinations of two commands:
sudo
: superuser do, 允许被授权的用户以超级用户(root)的身份执行单个命令su
: substitute user, 切换用户, 不指定用户时切换到 root 用户sudo su
: 先使用 sudo 提升权限为 root,再用 su 切换到 root 会话
It is worth noting that there are two concepts in the above description, root user and root session.
When we use the sudo
command, we can get the root privilege with current user’s password and then enter into the root session.
When we use the su
(su root) command, we can also get the root privilege, but at this time, we need use the root user’s password and then enter into the root session.
The difference between sudo
and sudo su
lies in the duration of root privilege.
Maybe we have a question is that when we execute the sudo su
command, we can also substitute to root user, so what is the the difference between su
and sudo su
?
It lies in the user who get the root privilege, the former is root user itself, the latter is current user. And the system will record the action of sudo
command, so when some errors appear, we can locate the user who create it quickly.
云服务器
本地免密登录
文件相关
ls命令各字段分布
在使用ls获取文件的各项信息时,常用的选项包括如下几种:
-a
:展示包括隐藏文件在內的所有文件-l
:打印文件的详细信息-h
:以人类可以理解的格式输出文件大小-G
:以彩色文本输出结果
关于时间信息
-U
:展示文件的创建时间-l
:展示文件最后的修改时间-c
:展示文件状态最后改变时间-u
:用文件最后的访问时间代替原始-l
展示的最后修改时间
关于排序
-t
:首先根据时间戳降序排序,当时间戳相同时,按照文件名字典序生序排列-S
:字典序排序前按照文件大小降序佩列
|
|
常见的文件类型
-
(短划线):普通文件d
:目录l
:符号链接(软链接)c
:字符设备文件b
:块设备文件s
:套接字文件p
:命名管道(FIFO)
文件权限解释
文件分为普通文件和目录文件。 对于普通文件,读写执行权限是比较好理解的; 对于目录文件,具有读权限意味着可以读取当前目录下的文件,具有写权限意味着可以更改目录结构,更改目录结构和更改目录下文件的内容是不同的,修改目录下一个普通文件中的内容并不会改变目录结构,在目录下新增/删除文件/目录才会更改目录结构;具有可执行权限意味着可以进入当前目录
关于时间
时间有哪些分类?
- 访问时间(access time)- atime
- inode 创建时间(inode creation time)
- 改变时间(change time)- ctime
- 修改时间(modification time)- mtime
通过
ls
命令的不同选项可以查询到不同的时间,查询创建时间采用ls -lU
,查询访问时间采用ls -lu
,查询改变时间采用ls -lc
,查询修改时间采用ls -l
1
在以上4种时间中,inode创建时间是很好理解的,问题在于如何区分其他三种时间类型,
- 向文件写入会修改atime,ctime和mtime
- 文件权限和属主的变更会修改atime和ctime
- 读文件会修改atime
从以上三种情形可以看出,修改是指文件内容的修改,改变是指文件状态(文件属性+文件内容)的改变,访问操作涉及的范围则相对宽泛,无论读、写还是状态的改变都会涉及到文件的访问。
挂载与卸载
“挂载”的本质是: 2
A mount point is a directory to access your data (files and folders) which is stored in your disks.
所以挂载无非是给设备或者目录创建了一个入口。
设备挂载
mount <device path> <directory path>
: 将设备 <device path>
挂载到 <directory path>
查找磁盘设备时,可以借助 lsblk
命令以及 /dev/
下列举的设备。
从挂载点的本质来说,就是为指定的设备 device 创建了 directory 这个入口,通过 directory 可以访问到 device 上的数据。
目录挂载
mount --bind <directory-a path> <directory-b path>
: 将 directory-a 绑定到 directory-b
其实这样说不是很好理解,但是如果我们参照设备绑定参数的含义以及挂载点的本质来理解,directory-b 实际就是 directory-a 的一个入口,在访问 directory-b 时实际就是在访问 directory-a。
实际上,我们可以将两种方式进行组合使用,首先使用 mount /dev/nvme1 /mnt/extra
,然后使用 mount --bind /mnt/extra /home
.
最终的效果是: 访问 /mnt/extra
就是在读取 nvme1 这一磁盘上的数据;访问 /home
实际访问的是 /mnt/extra
,本质上访问的还是 nvme1 磁盘上的数据。
实际上,示例达到的效果无非是访问 /home
实际访问 /mnt/extra
,这一效果通过软连接完全可以实现,我们只需要用 /mnt/extra
创建一个 /home
的软链接即可.
所以说在提及目录挂载时,我们可以同软硬链接进行比较,硬链接无法链接目录,而软链接虽然可以链接目录,但在有些程序里对符号链接(软链接)的支持并不友好,这个时候,我们就可以通过 mount --bind
命令来将两个目录链接起来。
需要额外注意的是 directory-a 和 directory-b 的权限,在绑定挂载完成后,directory-a 就是 directory-b 的别名,所以此目录的权限就是 directory-b 的权限,因此一种好的方式是在挂载之前,就将 directory-b 及其子目录和文件 的权限修改为与 directory-a 权限相同。
卸载
对于设备挂载,卸载的应该是挂载点这个目录,而不是这一设备,这一点并不难理解。
对于目录挂载mount --bind <directory-a path> <directory-b path>
,在逻辑上我们可以将 directory-a
就看为一台设备,directory-b
是这台设备的挂载点,卸载时只需要卸载这一挂载点即可。
shell
更多内容见shell 十四问
查看当前可用shell
cat /etc/shells
修改默认shell
使用
chsh
工具chsh --shell /bin/zsh username
修改
/etc/passwd
文件
特殊变量
- $0 - 脚本名
- \$1 到 \$9 - 脚本的参数。$1 是第一个参数,依此类推
- $@ - 所有参数
- $# - 参数个数
- $? - 前一个命令的返回值(返回码)。返回值0表示正常执行,非0表示有错误发生
- $$ - 当前脚本的进程识别码
- !! - 完整的上一条命令,包括参数。常见应用:当你因为权限不足执行命令失败时,可以使用 sudo !!再尝试一次。
- $_ - 上一条命令的最后一个参数。如果你正在使用的是交互式 shell,你可以通过按下 Esc 之后键入 . 来获取这个值。
返回码可以和逻辑运算符(
||
和&&
)在脚本中搭配使用
非常用变量
- $* - 把所有命令行参数看为一个字符串
- $@ - 把所有命令行参数看为一个个独立的字符串
替换技术
参数替换 ${}
在${}
中,通过#
、%
和/
符号能够实现字符串处理
|
|
常见的字符串操作根据修改位置分为:左侧和右侧,根据动作类型分为:删除和替换,根据匹配长度分为:最短匹配和最长匹配
实际的可选操作是以上几种分类方法的组合,具体方式如下
注:以下示例使用的变量为var="/dir1/dir2/dir3/my.file.txt"
左侧删除最短匹配
${var#pattern}
:#表示左侧、删除操作、进行最短匹配,即删除左侧和pattern匹配的最短部分${var#*/}
:pattern为*/,结果为dir1/dir2/dir3/my.file.txt左侧删除最长匹配
${var##pattern}
:##表示左侧、删除操作、进行最长匹配,即删除左侧和pattern匹配的最长部分${var##*/}
:pattern为*/,结果为my.file.txt右侧删除最短匹配
${var%pattern}
:%表示右侧、删除操作、进行最短匹配,即删除右侧和pattern匹配的最短部分${var%/*}
:pattern为/*,结果为dir1/dir2/dir3右侧删除最长匹配
${var%%pattern}
:%%表示右侧、删除操作、进行最长匹配,即删除右侧和pattern匹配的最长部分${var%%/*}
:pattern为/*,结果为空值替换
${var/pattern/replace}
:表示用replace替换字符串中的pattern,且只替换左侧第一个匹配项${var/dir/path}
:把左侧第一个dir替换为path,结果为/path1/dir2/dir3/my.file.txt${var//pattern/replace}
:表示用replace替换字符串中的pattern,且替换全部匹配项${var//dir/path}
:把全部的dir替换为path,结果为/path1/path2/path3/my.file.txt
String slicing is used to extract substrings from a string. Its syntax shows below:
|
|
- start: Represents the starting position of the slice (inclusive). If not specified, it defaults to 0.
- length: Repersents the length of substring what you want to get.
算术替换 (())
和 $(())
|
|
文件名替换
通过通配符匹配文件名
|
|
命令替换 `` 或 $()
shell会首先执行反引号或$()
包裹的内容,将执行结果作为整个替换部分的值
|
|
进程替换 <()
和 >()
进程替换在临时文件和管道操作符之外提供了一种新的方式,这种方式能够更加方便地处理命令之间的输入和输出关系 小括号内包含着命令,进程替换会将小括号内命令的执行结果存入一个临时文件中,同时返回该临时文件的路径
|
|
diff需要两个文件作为输入,因此需要两个ls命令首先将执行结果放入一个文件中,再把文件路径作为输入值传递给diff命令,这一执行顺序刚好符合进程替换的执行顺序
如何确定临时文件的位置?
由于进程替换的返回值就是临时文件的路径,因此只需要在小括号内输入任意命令,通过echo
命令输出进程替换的返回值即可显示临时文件的路径
|
|
注:
- true也是一条命令,不进行操作只返回true值
- /dev/fd 是一个特殊的目录,用于表示进程的文件描述符(File Descriptors),后面的11并不是固定值,只是在执行命令时获得的临时文件描述符为11
流及其重定向
在了解具体的流重定向方法之前,我们需要首先了解Linux下3种特殊的设备:stdin
, stdout
, stderr
。它们都位于/dev/
目录下,详细信息如下:
|
|
下面要使用的0,1,2实际指代的就是这3类设备
更详细的内容请见3.6 Redirections | Linux manual, 以下只是部分内容。
输入流重定向<
|
|
- 0<表示将
cat
命令的标准输入(stdin)从名为hello.txt的文件中读取数据,默认情况下,直接使用<
实现输入流重定向。之所以用0表示,是因为stdin实质上是一个链接文件/dev/stdin,其指向/dev/fd/0这个字符设备文件
输出流重定向>
1>
表示将 标准输出(stdout) 从终端重定向至文件,由于被重定向因此终端不再显示结果。之所以用1表示是因为stdout->链接文件/dev/stdout->字符设备文件/dev/fd/12>
表示将 标准错误输出(stderr) 从终端重定向至文件。echo hello
的stdout结果是hello,stderr结果是空。stdout未发生重定向,因此终端显示hello,stderr的空结果被重定向至hello.txt。在一般情况下,stdout和stderr都是定向到终端的,通过1>
和2>
可以区分二者。之所以用2表示是因为stderr->链接文件/dev/stderr->字符设备文件/dev/fd/2&>
和>&
表示将 标准输出和标准错误输出 统一重定向至文件
在不加数字时,即
>
则默认表示对 标准输出(stdout) 进行重定向
|
|
以上描述的都是将内容重定向至文件,如果想要重定向到管道(stdout / stderr)需要添加&
符号,以便于区分普通文件名和管道名称
2>&1
表示将标准错误重定向至标准输出(stdout)1>&2
表示将标准输出重定向至标准错误(stderr)
结合重定向至文件和重定向至管道,可以把所有输出内容全部重定向至文件,如以下代码所示
|
|
需要注意的是,上述重定向的顺序不能更改。大致可以理解为shell在重定向时是顺序处理的,如果标准错误的重定向先于标准输出的重定向,那么结果将是标准错误仍然会到达标准输出原有的输出端,并不会到达文件
输入流和输出流合用
|
|
向文件追加内容>>
与输出流重定向类似,存在
1>>
和2>>
,表示以追加的形式进行stdout和stderr的重定向
|
|
注:需要明确的是在shell中执行都都是一个个的程序,即使是
sudo
也只是一个特殊的程序而已。程序的调用执行是由shell负责的, 在使用重定向和管道时,前后要执行的程序是不知情的,重定向和管道是由shell负责的。 因此对于命令sudo echo x > file.txt
,假设当前用户并不具备file.txt的写权限,即使前面添加了sudo
,执行结果依然是无权限,这是因为该命令的执行逻辑为,shell以echo x
作为参数执行sudo
程序,然后将结果输入到file.txt中,实际的输入过程shell仍然是以当前用户身份进行的,并不是以root身份进行的,因此操作仍然无权限。 在这种情况下,echo x | sudo tee file.txt
就可以正常执行,这是因为实际是以root身份执行写入操作的
条件判断
test
[
[[
其中[
和test
是等效的命令,[
也称为test
的别名。三者具体的区别见如下站点
What is the difference between test, [ and [[ ?
通配符
*
:匹配任意长度的字符,包括空字符 *.txt 可以匹配所有以.txt结尾的文件?
:匹配单个字符 file?.txt 可以匹配file1.txt、file2.txt等[]
:匹配方括号内的任意一个字符 [abc]file.txt 可以匹配afile.txt、bfile.txt、cfile.txt{}
:用于生成多个相关字符串 file{1,2}.txt -> file1.txt file2.txt file{a..d}.txt -> filea.txt fileb.txt filec.txt filed.txt
..
为范围操作符
Emacs 和 vi 模式切换
如何在terminal下使用vi的操作方式? 见Chapter 4: The Z-Shell Line Editor 4.1.1: The simple facts
job control
如何管理background job?
使用
jobs
命令可以列出当前终端下的所有job
使用kill
命令结合各种信号,以下是几种常用的信号及其解释
SIGSTOP
和SIGCONT
用于暂停/恢复进程的执行,SIGSTOP
特殊在于其无法被捕获、处理或忽略 恢复进行执行还可以使用fg
(foreground)和bg
(background)命令,分别控制进程在前台和后台继续执行SIGHUP
用于通知进程其终端连接已断开的一种信号,当一个终端连接被关闭时,该终端上运行的所有进程都会收到 SIGHUP 信号(和此信号相关的有一个nohup
命令(Allows for a process to live when the terminal gets killed),通过nohup
和&
的结合使用可以实现后台运行进程且终端关闭后进程不被终止的效果)SIGINT
通常是由用户在终端上按下Ctrl+C发送给程序的。它用于请求中断程序的执行。默认情况下,大多数程序会响应SIGINT信号并进行清理工作后正常退出SIGTERM
通常不是由用户手动触发,而是由系统或其他进程发送给程序,用于请求程序停止执行并正常退出SIGKILL
用于强制终止进程的执行,当进程收到信号时,无论其当前状态如何,该进程都会立即被终止,并且没有机会进行任何清理或处理操作
对于以上内容,难点在于如何理解后4种信号,他们都会让进程终结,但是会应用于不同场景,更加常用的是SIGINT
和 SIGKILL
process control
SSH
If you want a remote mechine excute a command or a script , you have two ways.
One is that you get a connection to the remote mechine firstly, and then excute a command or a script.
The other is that you can use a special format command. The command which you want to excute follows the ssh command. It looks like ssh user@hostnames <command>
.
More details can be found in ssh 教程
The configuration file of ssh is the ~/.ssh/config
, in this file, you can use a hostname, which can simplies the connection sentence for every time.
Common scenarios
- move files in this directory to an another directory
find . -type f -d 1 | xargs -I {} mv {} <target directory>
常见sheel脚本示例
- 统计当前目录下各文件行数以及总行数
|
|
注:该示例除了基本的变量替换以及条件判断,值得注意的一点就是
wc
在使用重定向符<
时,就无法再确定输入来自何文件,因此输出只会包含计算出的行数,不再包含文件名,刚好符合这里的用法
命令别名
- 直接
alias [alias name]='[command]'
,仅在当前会话中有效 - 修改
/root/.bashrc
,永久生效
注意:alias的
=
两侧不能包含空格
Symbolic link and Hard link
Please note that when you create a symbolic link, you ought to use the absolute path. If you use the relative path, when you excute the command ls -l
, you will find the target file of symbolic link is not the file what you want it to point to.
But you can use either relative path or absolute path to create a hard link.
Search command
man
apropos
: Use keyword to search command- tldr