MissingSemester(1):初识Shell以及Bash
概述:Shell是什么
如今的计算机有着多种多样的交互接口让我们可以进行指令的的输入,但是它们也从根本上限制了您的操作方式——你不能点击一个不存在的按钮或者是用语音输入一个还没有被录入的指令。 为了充分利用计算机的能力,我们不得不回到最根本的方式,使用文字接口:Shell
Shell的核心功能是一样的:它允许你执行程序,输入并获取某种半结构化的输出
接下来我们会使用Bourne Again SHell,简称bash.以Linux为例,我们按下ctrl+alt+T来打开它
初步使用Shell
shell的接口会告诉你主机名和当前的工作目录(位置)
另外,如果当前的输入框是以$开头,则是表面您现在的身份还不是root用户
在此时,我们可以输入命令并被shell解析,比如:
一些命令与操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| 在这里,我们的程序就是```echo```,而执行的参数是"hello" 
> 如果希望传递的参数包含空格,可以使用单/双引号 将其包裹,或者使用转义符号进行处理
```man+指令```:man指令可以获得对应命令的说明,比如```man echo```就可以获得一个echo命令的使用、参数、flag、option等信息。使用q来退出手册
```mkdir```:新建一个文件夹 ```cp```:copy,拷贝一份文件
```导航/切换```:shell 中的路径是一组被分割的目录,在 Linux 和 macOS 上使用 ```/``` 分割,而在Windows上是 ```\``` 如果某个路径以 ```/``` 开头,那么它是一个**绝对路径**,其他的都是**相对路径** 相对路径是指相对于当前工作目录的路径,当前工作目录可以使用 pwd 命令来获取
想要进行路径的切换,一般而言我们常用```cd+切换位置```来进行;此外,在路径中,可以使用```.```来表示当前目录,用```..```来表示上级目录
一般来说,当我们运行一个程序时,如果我们没有指定路径,则该程序会在当前目录下执行
```ls```:ls命令可以用来查看指定目录下包含哪些文件,我们利用第一个参数指定目录,否则 ls 会打印当前目录下的文件。具体有那些flag和option,可以通过```-h```,```-help```,或者```man xxx```查询
### 文件信息 我们在使用```ls -l```的时候会打印出详细信息,其中有一个十个字符组成的序列十分重要: 
我们按照```1|234|567|89A```的方式进行划分:第一个字符表示它是什么,比如这里的d就表示这是一个目录;而后面的九个字符每三个为一组,分别代表不同组所拥有的权限:**三组**分别是所有者、用户组、其它所有人;**三字符**则是r阅读权限,w写入权限,和x执行权限
## 程序执行 > 在 shell 中,程序有两个主要的“流”:它们的输入流和输出流。 当程序尝试读取信息时,它们会从输入流中进行读取,当程序打印信息时,它们会将信息输出到输出流中。
### 重定向、追加、管道 ```> file```:将输出定向到某个文件中 ```file >```:将某个文件的内容作为输出定向出来 
此外,可以使用```>>```来向一个文件**追加**内容,也就是往文件的末尾写入东西。
使用```|```可以**开启管道pipe**来连接两个程序,也就是说使用```A|B```把A程序的输出,作为B程序的输入来使用
### su超级用户 > 对于大多数的类 Unix 系统,有一类用户是非常特殊的,那就是:根用户(root user);通常在我们并不会以根用户的身份直接登录系统, 取而代之的是我们会在需要的时候使用 sudo 命令。顾名思义,它的作用是让您可以以 su(super user 或 root 的简写)的身份执行一些操作
```sudo+命令```可以在su身份下执行一些操作,通常在遇到**拒绝访问(permission denied)的错误**,我们可以通过在命令开头加入sudo来执行
## Shell的脚本
### 赋值 在bash中为变量赋值的语法是```A=b```,注意```A = b```(即使用空格隔开)是不能正确工作的,因为解释器会调用程序```A```并将```=```和```bar```作为参数
想要访问变量中存储的数值,类似指针,我们需要使用```$变量名```来访问
### 字符串 Bash中的字符串通过```'```和```"```分隔符来定义,但是它们的含义并不相同
以```'```即单引号定义的字符串为原义字符串,其中的**变量不会被转义** 而以```"```即双引号定义的字符串会**将变量值进行替换**
### 基础语法 和大多数编程语言一样,bash也支持那些常见的控制流关键字、函数等,比如下例就定义了一个创建并进入的函数: 
#### 参数表示 bash语言使用了不同的特殊变量来表示参数、错误代码、相关变量等内容,比如:
```bash $0:脚本名 $1-$9:脚本的参数,其实1是第一个参数 $@:所有的参数 $#:参数个数 $?:前一个命令的返回值 $$:当前脚本的进程识别码 !!:完整的上一条命令,包括参数 $_:上一条命令的最后一个参数
|
更完整的列表可以参考:https://www.tldp.org/LDP/abs/html/special-chars.html
命令通常使用 STDOUT来返回输出值,使用STDERR 来返回错误及错误码,便于脚本以更加友好的方式报告错误。 返回码或退出状态是脚本/命令之间交流执行状态的方式。返回值0表示正常执行,其他所有非0的返回值都表示有错误发生
流控制
退出码可以配合&&和||操作符来使用,进行对应的条件判断
同一行的多个命令可以使用;来分割
程序true的返回码一直为0;程序false的返回码永远是1
获取命令的输出/命令替换
当您通过 $(CMD)这样的方式来执行CMD这个命令时,它的输出结果会替换掉$(CMD)
例如我们使用for file in $(ls),shell首先将调用ls ,然后遍历得到的这些返回值
还有一个冷门的类似特性是 进程替换(process substitution), <( CMD ) 会执行 CMD 并将结果输出到一个临时文件中,并将 <( CMD ) 替换成临时文件名。这在我们希望返回值通过文件而不是STDIN传递时很有用。例如, diff <(ls foo) <(ls bar) 会显示文件夹 foo 和 bar 中文件的区别
在bash中进行比较时,尽量使用双方括号 [[ ]] 而不是单方括号 [ ],这样会降低犯错的几率,尽管这样并不能兼容sh
通配符和批量展开
通配符:类似正则表达式的,我们在进行匹配的时候可以使用?和*来匹配一个或者任意个字符
花括号展开:{}可以辅助展开一系列的指令,其中包含一段公共子串时,可以用花括号来自动展开这些命令。这在批量移动或转换文件时非常方便
查找文件
所有的类UNIX系统都包含一个名为find的工具,它是 shell 上用于查找文件的绝佳工具。find命令会递归地搜索符合条件的文件
例如:
除了列出所寻找的文件之外,find 还能对所有查找到的文件进行操作。这能极大地简化一些单调的任务
其它查找的程序
fd就是一个更简单、更快速、更友好的程序,它可以用来作为find的替代品,以模式PATTERN搜索的语法是fd PATTERN
locate使用一个由updatedb负责更新的数据库,在大多数系统中 updatedb 都会通过 cron 每日更新。
find 和类似的工具可以通过别的属性比如文件大小、修改时间或是权限来查找文件,locate则只能通过文件名。
想要了解更多的话,可以点击:https://unix.stackexchange.com/questions/60205/locate-vs-find-usage-pros-and-cons-of-each-other
查找代码
很多类UNIX的系统都提供了grep命令,它是用于对输入文本进行匹配的通用工具
grep命令具有不少的option,比如:
-C:查找结果的上下文
-v:对结果进行反选
-R:递归地进入子目录并搜索
查找shell命令
history可以访问shell中的历史命令,这个命令会打印出shell中被输入的命令的记录;配合上grep,我们就可以对命令进行搜索,比如:
history | grep find会打印包含find子串的命令
对于大多数的shell来说,您可以使用 Ctrl+R 对命令历史记录进行回溯搜索。敲 Ctrl+R 后您可以输入子串来进行匹配,查找历史命令行。
小结
该部分只是稍微并很浅地总结了bash和shell的一些用法和属性,如果想要更好地使用它们,最好的办法莫过于亲自多用linux系统并查找手册与相关书籍