MS1+2 shell 学习笔记/shell使用技巧
介绍
Missing Semester 1 和 2 的学习笔记。
Course View + the shell : https://missing.csail.mit.edu/2020/course-shell/
Shell Tools and Scripting : https://missing.csail.mit.edu/2020/shell-tools/
主要讲了一些适用于 Bash(MacOS 和 Linux 的 默认shell)的知识,当然很多概念在其他 shell 中也有,不过名字可能不同。
笔记中不止涉及到了课程中讲的内容,还有些内容自己搜索补充了一下:
Bash条件等语句:https://blog.csdn.net/ceshiren_com/article/details/141930133
同时也懒得开一个新的文章了,干脆把其他的奇奇怪怪的 Bash 知识也放在这里了。
Shell 使用技巧
主要在 1. Course View + the shell 介绍,第二章也介绍了一点。
指令
date: 日期echo: 输出后续的内容,例如:echo "test"pwd: 输出 cmd 现在的工作目录。cd: 进入某个文件夹,cd ..进入上一级文件夹(可嵌套),cd HOME到当前用户主文件夹,cd ~去到根目录。cd -会让你回到上一次所在的目录,这在需要在两个目录间反复切换时很好用。ls: 列出当前所有文件,ls dir列出文件夹里面的所有文件和文件夹(不会递归)。ls -l会列出文件夹内更加详尽的信息,左边的字符为:第一个字符是类型:$\text{d(文件夹)/-(文件)}$,后面有三组三个字符($\text{rwx}$),分别代表拥有者、拥有组、所有人的权限:| 符号 |文件| 文件夹 |
|:——:|:—-:|:———:|
| - | 没有对应权限 | 没有对应权限 |
| r | 读取权限 | 读取文件列表 |
| w | 写入权限 | 修改文件列表 |
| x | 执行 | 进入文件夹的权限(需要当前和所有父文件夹的 x 权限) |$注:其实文件夹的权限可以看成是,对记录文件夹中文件信息的那个文件的权限。
man$(\text{manual})$ : 查询某个指令的用法(如果这个指令有 manual 界面的话)mkdir: 创建文件夹mv: 移动文件,mv source goal,如果goal是文件夹,则会移动到里面,如果不是,则会改名。which: 返回文件的路径chmod: 给某个文件加减权限,chmod +x file给 file 加可执行的权限(在下一节课写脚本的时候会用到)。cp$(\text{copy})$ : 复制文件。cat$(\text{capture})$ : 获取文件中的内容。touch: 更新文件的更改时间为当前时间,不存在则创建一个空文件。head/tail: 输出输入的开头或者结尾,-nk输出 $k$ 行。sudo/#$(\text{super do})$ : 用管理员权限进行某个指令。find: 寻找该文件夹中符合条件的文件或文件夹(会递归)。locate: 通过且只能通过文件名查找文件,查找速度更快,需要用updatedb维护数据库,与find更详细的对比。tee: 将标准输入既输入到文件中,也输入到标准输出中。rm/rmdir: 移除文件/空文件夹。curl:访问给定的 URL 并返回结果。tee(T型管,一个进两个出):从输入流读取输出到输出流和文件中。cut:切割输入流得到的内容。xdg-open:用合适的程序打开一个文件。diff:比较文件的不同。source:我目前只用它来加载过脚本。env:没怎么用过,但是在 shebang 行中使用可以提高脚本兼容性。export:也没怎么用过,好像是用来导出变量之类的东西。
输入输出流
一般每个进程都有三个主要的流:
- 标准输入流(STDIN),用于读入。
 - 标准输出流(STDOUT),输出结果
 标准错误流(STDERR),用于输出进程发生的错误。
<: 重定义标准输入流。>: 重定义标准输出流,输出前会清空目标文件,不存在则创建文件。(时间在所在命令执行之前,所以在某些指令中使用可能会涉及时机问题)。>>: 重定义标准输出流,输出时扩展目标文件内容,不会清空,不存在则创建文件。|: 将左边的标准输出作为右边的标准输入。- 每个进程都有三个主要的文件描述符:$0$ 标准输入,$1$ 标准输出,$2$ 标准错误,所以可以用 
1>/>来重定向标准输出,2>重定向标准错误流,或者使用&>将标准输入或输出一起重定向(也可以>file 2>&1)。 
表达式扩展
通配符:?/* 匹配一个/任意多个字符。例如:文件夹中有 bar,foo1,foo23 ,那么 rm foo? 删除 foo1 ,rm foo23 删除 foo1,foo23 。
大括号:{} ,里面放上可能匹配的若干模式串,例如:*.{png,jpg} 用于匹配图片。
替换
command substitution:$(CMD) 会执行 CMD 然后将其输出替换掉这一部分。
process substitution: <(CMD) 会执行 CMD 然后将其输出放在一个临时文件,将临时文件的名字替换掉这一部分。例如:diff <(ls d1) <(ls d2) 就必须用这个替换而不能用上面的,因为上面的部分会用输出替换掉 $(ls d1) ,然后这条指令就变成了比较两个文件夹内所有文件里的内容,然后就偏离预期了。
计算表达式:使用 []/[[]] ,里面放表达式即可,两者的区别似乎是后者有更多语法但兼容性更差,具体区别 here 。
一些简称
$PATH: 所有环境变量,环境变量是系统在寻找可执行文件时会搜索的目录。$HOME/~: 表示用户的主文件夹/home/user/: 表示根目录,ls /进入根目录,路径前面有没有/是区分相对路径和绝对路径的标志。
杂项
/sys文件夹中会将内核参数以文件的形式展现,通过修改这些文件可以起到配置某些系统功能的作用,例如用亮度之类的。/dev/null:可以理解为电子焚烧炉,不要的东西往里面丢就行了。
C-l会让当前行到 shell 顶部,但并不会清空 shell ,他只会在前面填充大段的空白达到类似清空的效果。- 命令行前的 
$表示现在处在用户环境,#表示管理员环境,使用sudo su/exit进入/退出。 ;隔开可以一行写多条指令。- 命令后加 
\可以另开一行,'可以开多行(在输入'结束),;可以一行输入多个命令。 
Bash 脚本
主要在 2. Shell Tools and Scripting 介绍。
Shell 中和在脚本中能使用的语法基本一样,这里主要介绍一般只会(不是只能)在脚本中使用的语法。
杂项
变量:foo=bar,这样会得到一个值为字符串 bar 的变量 foo,$foo 引用该变量。
shebang 行 :在脚本的第一行,用于标明这个脚本使用的执行程序。例如一般 Bash 脚本的 shebang 行:#!/bin/bash 。
使用 env 来写 shebang 行可以提高脚本兼容性,例:#!/usr/bin/env python ,会让程序使用 env 去 Path 中寻找 Python 的可执行程序作为这个脚本的执行程序。
source A 会让 CMD 加载脚本 A ,这会运行其中的指令,和 ./A 的区别在于,前者在当前环境,而后者是新开了一个环境,所以脚本中如果有 cd 之类的指令,前者会影响当前 shell ,后者不会,包括定义的函数和参数也是。
条件/循环语句
条件语句:
1  | if [ expression_1 ] && [expression_2] ;  | 
for循环语句:
1  | for variable in list  | 
while循环:
1  | while [ expression ];  | 
函数:
1  | function_name() {  | 
特殊含义的参数
$0:脚本名。$1to$9:给脚本的第 $i$ 个参数。$@:所有参数。$#:参数数量。$?:上一条命令的返回代码(在这个参数使用前的上一条命令,不是脚本前的)。$$:当前脚本的进程标识数(PID)。!!:上一条完整的指令,包括参数。(一种用处,在上一条指令因为权限不够执行失败时,用管理员再执行一次)$_:上一条的最后一个参数。
工具/扩展推荐
- shellcheck (https://github.com/koalaman/shellcheck):检查你的 Bash 脚本的语法错误。
 - TLDR (https://tldr.sh/):简化版的 
man,会提供所查询指令的一些比较常用的用法。 - fd (https://github.com/sharkdp/fd):语法更加人性化的 
find。 - locate ()
 
目前进度
第一课 note + 视频完成。
第二课 note 和视频都没完成。