# shell

## 复习命令

| 数据索引命令        | 数据处理命令        |
| ------------------- | ------------------- |
| 行检索：grep egrep  | 数据排序：sort      |
| 字符串检索： cut tr | 数据去重：uniq      |
|                     | 文本数据合并：paste |
|                     | 数据输出： tee      |
|                     | 数据处理xargs       |

### grep

grep负责从数据源中检索对应的字符串，**行**过滤。输出的时被匹配的那行。

`grep [options] "string" firename`

| 选项 | 功能                              | 备注                               |
| ---- | --------------------------------- | ---------------------------------- |
| i    | 不区分大小写，linux默认区分大小写 |                                    |
| v    | 反向查找，查找不包含              |                                    |
| w    | 按单词搜索                        | 必须是正确的单词                   |
| n    | 显示行号                          |                                    |
| A    | 显示匹配行以及后面多少行 -A 5     |                                    |
| B    | 显示匹配行以及后面多少行          |                                    |
| o    | 打印匹配关键字                    | 只显示匹配到的关键字<br />以列显示 |
| c    | 统计匹配到的次数                  | 只显示数字                         |
| r    | 逐层遍历目录查找                  |                                    |
| C    | 显示匹配前后多少行                |                                    |
| l    | 只列出匹配的文件名                |                                    |
| L    | 列出不匹配的文件名                |                                    |
| e    | 使用正则表达式                    |                                    |
| E    | 使用扩展正则表达式                |                                    |
| ^key | 以关键字开头                      |                                    |
| key$ | 以关键字结尾                      |                                    |
| ^$   | 匹配空行                          |                                    |

### cut

cut用于数据截取

`cut 选项 "文件"`

| 选项 | 功能                            | 备注                                                         |
| ---- | ------------------------------- | ------------------------------------------------------------ |
| c    | 以字符串为单位进行分割          | 截取字符串长度由后面数字确定                                 |
| d    | 自定义分隔符，默认使用制表符\t  | 自定义字符使用""                                             |
| f    | 与 -d一起使用，指定显示那个区域 | 多列之间可以加","分隔<br />连续多列之间家"-"连接<br />多列之间会携带分隔符 |

### tr

tr用来对标准输入中通过替换或删除操作进行字符转换，主要用于删除文件中控制字符或进行字符转。

使用tr时要转换两个字符串，第一个用于查询，第二个用于处理各种转换。

`commands | tr [options] "string1" "string2 < "filename"`

| 选项 | 功能                                                         | 备注 |
| ---- | ------------------------------------------------------------ | ---- |
| d    | 删除字符串中所有输入字符                                     |      |
| s    | 删除所有重复出现字符序列，只保留第一个。<br />将重复出现的字符串压缩为一个字符串。 |      |

### sort

sort是将文件的**每一行作为一个单位**，从**首字符向后**，一次按照ASCII码进行比较，最后将他们**升序**输出。

`sort [options] [filename]`

| 选项 | 功能                       | 备注         |
| ---- | -------------------------- | ------------ |
| u    | 去除重复行                 | 只保留第一行 |
| r    | 降序排列                   |              |
| o    | 将排序结果输出到文件中     |              |
| n    | 以数字排序，默认是字符排序 |              |
| t    | 分隔符                     |              |
| k    | 第N列                      |              |
| b    | 忽略前导空格               |              |
| R    | 随机排序，每次结果都不同   |              |

### uniq

uniq能够去除连续的重复行。**去重前先要排序**

`uniq [options] [filename]`

| 选项 | 功能           | 备注 |
| ---- | -------------- | ---- |
| i    | 忽略大小写     |      |
| c    | 统计重复行次数 |      |
| d    | 只显示重复行   |      |

 ### tee

tee能够实现双向输出，将屏幕输出文件写入到文件或输出到屏幕。和"<<" ">>" "<" ">" 这几个工具一样。

`somecommand | tee`

| 选项 | 功能           | 备注 |
| ---- | -------------- | ---- |
| a    | 双向追加重定向 |      |

### paste

paste工具用于合并文件行输出到屏幕，不会改动源文件。

`paste [options] [file1] [file2] ...`

| 选项 | 功能                                    | 备注 |
| ---- | --------------------------------------- | ---- |
| d    | 自定义间隔符                            |      |
| s    | 将每个文件按照一行输出，航宇航以tab间隔 |      |

### xargs

管道命令，将上一个命令的输出作为下一个命令的输入，做的是**数据源**，一般使用"|"符号。

xargs命令，将上一个命令的输出作为下一个命令的**参数**。一般是和管道命令一起使用。

`"[somecommand]|[filename]" | xargs [options] command`

| 选项    | 功能                                                         | 备注 |
| ------- | ------------------------------------------------------------ | ---- |
| -a file | 从文件读入作为输入                                           |      |
| -E flag | flag必须是一个以空格分割的标志<br />当xargs分析道flag时就停止 |      |
| -p      | 没执行一次就询问下用户                                       |      |
| -n num  | 表示执行的时候一次用的参数的个数，默认是全部使用             |      |
| -t      | 先打印命令，然后执行，不询问用户是否执行。                   |      |
| -i/-I   |                                                              |      |
| -r      | 当xargs的输入为空的是停止xargs                               |      |
| -d      | 分隔符，默认的分隔符是回车                                   |      |

### shell字符

| 符号                     | 功能                                                   | 备注 |
| ------------------------ | ------------------------------------------------------ | ---- |
| ！                       | 执行历史命令                                           |      |
| $                        | 读取变量中的内容                                       |      |
| + - * / %                | 对应数学运算 加 减 乘 除 取余                          |      |
| &                        | 后台执行                                               |      |
| ;                        | 在一行同时执行多个命令                                 |      |
| \                        | 转义字符                                               |      |
| ``                       | 反引号，在命令中执行命令                               |      |
| ''                       | 单引号，脚本中字符串使用引号引用起来，单引号不解释变量 |      |
| ""                       | 双引号，双引号能解释变量                               |      |
| *                        | 星号，通配符，匹配所有                                 |      |
| ~                        | 家目录，当前用户家目录                                 |      |
| ？                       | 问号，通配符，匹配一个字符                             |      |
| [list]                   | 匹配list中的任意单个字符                               |      |
| [!list]                  | 匹配除list中的任意单个字符                             |      |
| {string1, string2, ....} | 匹配字符串，连续字符可以使用{1..5}表示                 |      |

### 实战思路

1. 先截取行
2. 统一数据格式
3. 截取字符串
4. 处理字符串

## bash shell基本特性

### 命令补全和自动补全

“tab”只能补全命令和文件。也可以使用“bash-completion”软件实现子命令补全。

### 常见的快捷键

| 按键         | 功能                       | 备注 |
| ------------ | -------------------------- | ---- |
| ^c           | 终止前台运行的程序         |      |
| ^z           | 将前台运行的程序挂起到后台 |      |
| ^d           | 退出 等同于 exit           |      |
| ^l           | 清屏                       |      |
| ^a 和 "home" | 光标移到命令行的最前端     |      |
| ^e 和 "end"  | 光标移动到命令行的后端     |      |
| ^u           | 删除光标前所有字符         |      |
| ^k           | 删除光标后所有字符         |      |
| ^r           | 搜索历史命令               |      |

### 变量

变量是编程中最常用的一种临时在内存存取数据的一种方式。

#### 什么时候定义变量

如果某个内容需要多次使用，并且在代码中重复出现，那么可以用变量代表该内容。这样在修改内容的时候，仅仅需要修改变量的值。

在代码运作的过程中，可能会把某些命令的执行结果保存起来，后续代码需要使用这些结果，就可以直接使用这个比变量。

#### 定义一个变量

定义变量格式：`变量名=变量值`

**在shell编程中的变量名和等号之间不能有空格**

##### 变量命名规则：

* 命名只能使用英文字母，数字和下划线，首个字母不能以数字开头。
* 中间不能有空格，可以使用下划线"_"。
* 不能使用标点符号。
* 不能使用bash里的关键字（可用help命令查看保留关键字）。

> 注意：字符串要用单引号或双引号引起来
>
> 注意：建议变量名为大写，和命令区分

#### 取消变量

unset命令可以取消当前环境中的变量。

#### 有类型变量

declare用来定义有类型的变量。

`declare [options] 变量名=变量值`

| 选项 | 功能                       | 备注                                        |
| ---- | -------------------------- | ------------------------------------------- |
| -i   | 将变量看成整数             |                                             |
| -r   | 是变量只读                 | 只读变量的值无法被改变<br />并且不能为unset |
| -x   | 标记变量通过环境导出export |                                             |
| -a   | 指定为索引数组（普通数组） |                                             |
| -A   | 指定关联数组               |                                             |

#### 变量分类

系统中的变量根据作用域及生命周期可以分为四类：本地变量、环境变量、全局变量、内置变量。

##### 本地变量

用户自定义的变量，定义在脚本或者当前终端中，脚本执行完毕或终端结束变量失效。

##### 环境变量

定义在用户家目录下的.bashrc或.bash_profile文件中，用户私有变量，只能在本用户使用。

>  查看当前用户的环境变量 `env`
>
> 查询当前用户的所有变量（临时变量与环境变量） `set`
>
> 将当前变量编程环境变量：`export 变量名=变量值`

##### 全局变量

使用export命令将本地变量输出为当前shell中的环境变量，所有用户以及shell都可以使用，可以在"/etc/profile /etc/bashrc"下永久定义。

##### 内置变量

系统变量（内置bash中变量）：shell本身已经固定好了他的名字和作用。

| 变量       | 值                                                           |
| ---------- | ------------------------------------------------------------ |
| #?         | 上一条命令执行后的返回状态<br />退出状态值为0表示执行成功<br />退出状态值为非0表示执行失败<br />退出状态值127表示"command not found"<br />退出状态为126，表示找到了该命令但无法执行（权限不足）<br />退出状态值为1&2，表示没有哪个文件或目录 |
| $$         | 当前所在进程的进程号                                         |
| $!         | 后台运行最后一个进程号                                       |
| !$         | 调用最后一条命令历史中的参数                                 |
| !!         | 调用最后一条历史命令                                         |
| $#         | 脚本后面连接的参数个数                                       |
| $*         | 脚本后面所有的参数，参数当成一个整体输出，每一个变量参数之间以空格隔开 |
| $@         | 脚本后面所有的参数。参数是独立的，也是全部输出               |
| $0         | 当前执行的进程名/程序名                                      |
| $1~$9      | 位置参数变量                                                 |
| ${10}~${n} | 扩展位置参数变量，第十个位置变量必须用{}括起来               |

##### 总结

| 变量类型 | 作用域                         | 生命周期           |
| -------- | ------------------------------ | ------------------ |
| 本地变量 | 当前shell环境（子shell不能用） | 脚本结束或终端结束 |
| 环境变量 | 当前shell或者子shell           | 当前进程结束       |
| 全局变量 | 所有用户及shell环境            | 关机               |
| 内置变量 | 所有用户及shell环境            | 关机               |

#### 读取变量

使用读取变量内容符。

可以使用”{}“来区分变量长度

`$变量名` `${变量名}`

> 在变量读取过程中，默认单引号不解释变量。
>
> 如果必须使用单引号，还要读取变量的值，可以使用eval命令 `eval echo '$变量名'`

## shell 用户交互

#### read命令

read命令默认接受键盘的输入，回车符代表输入结束，一般应用在人机交互中。

`read [opeions] "显示字符"`

| 选项 | 功能           | 备注 |
| ---- | -------------- | ---- |
| -p   | 打印信息       |      |
| -t   | 限定时间       |      |
| -s   | 不显示输入字符 |      |
| -n   | 输入字符个数   |      |

## shell 运算详解

### 赋值运算

赋值运算符"="

> 字符串必须用引号引起来。

### 算数运算

运算符与命令

| 符号 | 功能 |
| ---- | ---- |
| +    | 加   |
| -    | 减   |
| *    | 乘   |
| /    | 除   |
| %    | 取余 |
| **   | 开方 |

| 运算命令 | 功能                                                         | 示例                       |
| -------- | ------------------------------------------------------------ | -------------------------- |
| -expr    | 只能做整数运算，格式比较古板，注意空格。                     | expr 1 + 1                 |
| -let     | 只能做整数运算，且运算元素必须是变量，无法直接对证书做运算。 | let a=100+3                |
| -$(())   | 双小圆括号运算，在shell中(())也可以用来做数学运算            | echo $(( 1+1 ))            |
| -bc      | 浮点运算是采用命令的组合方式来实现的 `echo "scale=N;表达式"|bc` | echo "scale=2;100/3" \| bc |

### 比较运算

| 精确比较 | 模糊比较       |
| -------- | -------------- |
| -eq 等于 | -ne 不能与     |
| -gt 大于 | -ge 大于或等于 |
| -lt 小于 | -le 小于或等于 |

### 字符串比较运算

| 运算符 | 解释                      |
| ------ | ------------------------- |
| ==     | 等于                      |
| !=     | 不等于                    |
| -n     | 检查字符串的长度是否大于0 |
| -z     | 检查字符串的长度是否为0   |

> 字符串比较中，字符串必须用引号引起来

### 逻辑运算

| 运算符 | 解释       |
| ------ | ---------- |
| &&     | 逻辑与运算 |
| \|\|   | 逻辑或运算 |
| ！     | 逻辑非运算 |

### 文件判断

在linux中，一切接文件，对文件系统的操作其实可以狭隘的理解为对文件的操作。如果希望对文件类型和权限或者两者文件做新旧或者是否同一个文件进行判断。

#### test 命令

test命令可以检测文件类型和比较运算

`test [options] 表达式`

## shell 数组

#### 数组介绍

数组可以让用户一次赋予多个值，需要读取数据时只需通过索引调用就可以方便读出了。

普通数组：只能使用整数作为数组索引（元素的索引）
关联数组：可以使用字符串作为数组索引（元素的索引）

#### 普通数组

##### 数组定义

`数组名称=（元素1 元素2 元素3 ...)`

##### 数组赋值

* 一次赋一个值

  `变量名=变量值`

  ``` shell
  array[0]=v1
  array[1]=v2
  array[2]=v3
  ```

* 一次赋多个值

  `数组名=(元素1 元素2 元素3 ...)`

  ``` shell
  array=(var1 var2 var3 var4)
  array1=(`cat /etc/paaswd`)	# 将文件中每一行赋值给array1数组
  array2=(`ls /root`)
  array3=(harry amy jack "Miss zhang")
  array4=(1 2 3 4 "hello world" [10]=linux)
  ```

##### 数组取值

`${数组名称[数组索引]}`

> 索引：默认情况下索引是指数组中的元素[存在之]在数组中的顺序，从0开始计数，关联数组除外。
>
> | 元素 | var1 | var2 | var3 | var4 |
> | ---- | ---- | ---- | ---- | ---- |
> | 索引 | 0    | 1    | 2    | 3    |



#### 关联数组

##### 数组定义

关联数组使用首要要申明该数组为关联数组

`declare -A 数组名称`

##### 数组赋值

* 一次赋一个值

  `数组名[索引]=变量值`

  ``` shell
  asso_array[linux]=one
  asso_array[java]=two
  asso_array[php]=thress
  ```

* 一次赋多个值

  `数组名=([索引]=变量值 [索引]=变量值 [索引]=变量值 )`

  ``` shell
  asso_array=([name1]=harry [name2]=jack [name3]=amy [name4]="Miss zhang")
  ```

* 查看关联数组

##### 关联数组取值

`${asso_array[索引]}`

## 流程控制

### if判断语句

#### 单if语法

if语句一般应用在程序需要进行判断的时候。

单if语法适用于只需要一步判断，条件返回**真**干什么。

语句格式：

```shell
if [condition]		# condition 值为 true or false
	then			# 条件为真的时候执行
		commands	# 代码块，一行或多行代码
fi					# 语句的结束
```



#### if...else语句

![shell-ifelse-流程图](C:/Users/tao41/Pictures/typora/shell/shell-ifelse-流程图-16371978636001.png)

适用于两步判断，条件为**真**干什么，条件为**假**干什么。

语句格式：

``` shell
if [ condition ]
	then
			commands1
else
			commands2
fi
```

 ![shell-ifelse-流程图](C:/Users/tao41/Pictures/typora/shell/shell-ifelse-流程图.png)

#### if...elif...else

适用于多余两个以上的判断结果，也就是一个以上的判断条件。

语句格式：

``` shell
if [ condition ]
	then
		command1
elif [condition ]
	then
		commands2
......
else
		comandsX
fi
```

![shell-ifelseif-流程图](C:/Users/tao41/Pictures/typora/shell/shell-ifelseif-流程图.png)

### for语句

for语句一般用在已知循环次数的循环中







