forked from study-area-cn/learn-linux-basic
初步完成shellscript
This commit is contained in:
parent
258025a5b8
commit
f6f669febd
|
@ -24,7 +24,7 @@
|
||||||
- [学习Shell](./shell_and_shell_script/learn_shell.md)
|
- [学习Shell](./shell_and_shell_script/learn_shell.md)
|
||||||
- [Job]()
|
- [Job]()
|
||||||
- [Vim编辑器](./shell_and_shell_script/vim_editor.md)
|
- [Vim编辑器](./shell_and_shell_script/vim_editor.md)
|
||||||
- [Shell Script基本语法]()
|
- [Shell Script基本语法](./shell_and_shell_script/shell_script_basic.md)
|
||||||
- [条件判断语句]()
|
- [条件判断语句]()
|
||||||
- [循环]()
|
- [循环]()
|
||||||
- [函数]()
|
- [函数]()
|
||||||
|
|
|
@ -34,6 +34,18 @@ Linux 中,每个文件夹下,都有两个特殊的目录,就是`.`和`..`
|
||||||
|
|
||||||
## 基本操作
|
## 基本操作
|
||||||
|
|
||||||
|
### `echo` 输出字符
|
||||||
|
|
||||||
|
`echo` 的本意是“回声”,因为 `echo` 命令就是把你给它的参数输出一遍。你说什么它就回什么,和回声一样。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo 你想说的任何内容
|
||||||
|
```
|
||||||
|
|
||||||
|
> echo 命令可以使用在内容前加上 `-e`,就是开启转义(就是把 `\` 和下一个字符看作一个字符),例如 `\n` 是换行,更多的转义内容可自行查找。
|
||||||
|
>
|
||||||
|
> echo 是最简单的 Linux 命令了,但是在后面的用处会十分的大。
|
||||||
|
|
||||||
### `ls` 列出文件
|
### `ls` 列出文件
|
||||||
|
|
||||||
`ls`,顾名思义,就是 list,列出当前目录下的文件,他的基本使用方法也很简单:
|
`ls`,顾名思义,就是 list,列出当前目录下的文件,他的基本使用方法也很简单:
|
||||||
|
|
|
@ -46,15 +46,25 @@ command [options] [arguments]
|
||||||
|
|
||||||
## 变量
|
## 变量
|
||||||
|
|
||||||
Shell 中的变量分为环境变量和用户变量,环境变量是Shell启动时自动设置的变量,用户变量是用户自定义的变量。
|
Shell 中的变量分为局部变量、系统变量和全局变量,系统环境变量是 Shell 启动时自动设置的变量,局部变量和全局变量是用户自定义的变量。
|
||||||
|
|
||||||
用户变量可以通过 `export` 命令设置为临时环境变量,例如:
|
### 创建(定义)变量
|
||||||
|
|
||||||
|
我们可以用 `=` 创建一个局部变量,例如:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
GREET="Hello, World!"
|
||||||
|
```
|
||||||
|
|
||||||
|
> 这里注意等号的两边都不要有空格
|
||||||
|
|
||||||
|
变量可以通过 `export` 命令设置为全局变量,例如:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export GREET="Hello, World!"
|
export GREET="Hello, World!"
|
||||||
```
|
```
|
||||||
|
|
||||||
然后我们在这个 Shell 里启动一个新的 Shell,仍然可以在环境中找到这个变量。
|
然后我们在这个 Shell 里启动一个新的 Shell,仍然可以在环境中找到这个全局变量。而一般变量就找不到了。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash -c 'echo $GREET'
|
bash -c 'echo $GREET'
|
||||||
|
@ -62,12 +72,57 @@ bash -c 'echo $GREET'
|
||||||
|
|
||||||
> `export` 声明的变量只在当前环境下有效,如果你开启了个新的终端或者重启,那么这个环境就无效了
|
> `export` 声明的变量只在当前环境下有效,如果你开启了个新的终端或者重启,那么这个环境就无效了
|
||||||
|
|
||||||
用户变量可以通过 `declare` 命令声明,例如:
|
变量也可以通过 `declare` 命令声明,例如:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
declare USER_GREET="Hello, Shell"
|
declare USER_GREET="Hello, Shell"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> declare 默认声明的变量是局部的,和直接使用等号一样。使用 `-g` 可以设置为和 `export` 一样的全局变量。
|
||||||
|
|
||||||
|
我们可以使用 `declare -n` 可以显示定义的全部变量。
|
||||||
|
|
||||||
|
### 变量的作用范围(作用域)
|
||||||
|
|
||||||
|
我们执行以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 最外层的 Bash1
|
||||||
|
|
||||||
|
bash # 启动 Bash2
|
||||||
|
a=1
|
||||||
|
export b=2
|
||||||
|
declare c=3
|
||||||
|
echo "Bash2 a:${a} b:${b} c:${c}" # 观察更改前 Bash2 中变量的值
|
||||||
|
|
||||||
|
bash # 启动 Bash3
|
||||||
|
echo "Bash3 a:${a} b:${b} c:${c}" # 观察更改前 Bash3 中变量的值
|
||||||
|
a=4 # 更改 Bash3 中的变量
|
||||||
|
export b=5
|
||||||
|
declare c=6
|
||||||
|
echo "Bash3 a:${a} b:${b} c:${c}" # 观察更改后 Bash3 中变量的值
|
||||||
|
exit # 退出 Bash3
|
||||||
|
|
||||||
|
echo "Bash2 a:${a} b:${b} c:${c}" # 观察更改后 Bash2 中变量的值
|
||||||
|
exit # 退出 Bash2
|
||||||
|
|
||||||
|
echo "Bash1 a:${a} b:${b} c:${c}" # 观察 Bash1 中变量的值
|
||||||
|
```
|
||||||
|
|
||||||
|
会输出:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Bash2 a:1 b:2 c:3
|
||||||
|
Bash3 a: b:2 c:
|
||||||
|
Bash3 a:4 b:5 c:6
|
||||||
|
Bash2 a:1 b:2 c:3
|
||||||
|
Bash1 a: b: c:
|
||||||
|
```
|
||||||
|
|
||||||
|
我们会发现,使用等号定义的变量在里面的 Bash 获取不到,但是 export 获取的变量就能够访问。还有,在里面的 Bash 无论如何都影响不到外面的变量。
|
||||||
|
|
||||||
|
### 使用变量
|
||||||
|
|
||||||
变量可以通过 `${}` 或 `$` 符号来引用,例如:
|
变量可以通过 `${}` 或 `$` 符号来引用,例如:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -77,9 +132,13 @@ echo $USER_GREET
|
||||||
|
|
||||||
> 当变量的前后有别的内容紧挨着,那么只能使用 `${}`。
|
> 当变量的前后有别的内容紧挨着,那么只能使用 `${}`。
|
||||||
|
|
||||||
## 特殊的环境变量
|
如果使用的变量不存在,那么程序不会报错,会默默的把这个变量 **替换为空值**,这点需要十分注意。
|
||||||
|
|
||||||
Shell 中有一些特殊的环境变量,它们在 Shell 启动时自动设置,例如:
|
> 之前,有个软件的卸载用的 Shell Script 有一个 bug,会运行 `rm -rf $(INSTALL_PATH)/*`,但是这里的 `INSTALL_PATH` 变量可能会未定义,最终导致了清除了整个根目录。
|
||||||
|
|
||||||
|
### 系统变量
|
||||||
|
|
||||||
|
Shell 中有一些系统变量,它们在 Shell 启动时自动设置,例如:
|
||||||
|
|
||||||
- `$HOME`:当前用户的主目录。
|
- `$HOME`:当前用户的主目录。
|
||||||
- `$PATH`:可执行文件的搜索路径。
|
- `$PATH`:可执行文件的搜索路径。
|
||||||
|
@ -91,6 +150,12 @@ Shell 中有一些特殊的环境变量,它们在 Shell 启动时自动设置
|
||||||
|
|
||||||
> 在 Windows 中的 PATH 中有一条路径是 `.` 就是当前目录,而 Linux 中默认是不会搜索当前目录的。如果你在当前目录有一个 `run.sh`,那么你必须要使用 `./run.sh` 才能执行。
|
> 在 Windows 中的 PATH 中有一条路径是 `.` 就是当前目录,而 Linux 中默认是不会搜索当前目录的。如果你在当前目录有一个 `run.sh`,那么你必须要使用 `./run.sh` 才能执行。
|
||||||
|
|
||||||
|
另外还有以下几个特殊的系统变量:
|
||||||
|
|
||||||
|
- `$?`:上一个运行的程序的返回值(一个数字,通常 0 表示成功,其它数字表示错误,不同程序不同错误的返回值一般不同)
|
||||||
|
- `$0`:启动当前终端程序或者 ShellScript 的命令,如 `/bin/bash`
|
||||||
|
- `$#`:启动当前终端程序或者 ShellScript 的参数个数。
|
||||||
|
|
||||||
## 管道
|
## 管道
|
||||||
|
|
||||||
Shell 中的管道是链接两个命令的方式,管道遵守下面的格式。
|
Shell 中的管道是链接两个命令的方式,管道遵守下面的格式。
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
# Shell Script 基本语法
|
||||||
|
|
||||||
|
在前面,我们学习了 Shell 的基本命令以及变量,还有使用 Vim 编辑文件。我们是时候把这些放到一起来学习 Shell Script 了。
|
||||||
|
|
||||||
|
说是 Shell Script,本质上就是一堆命令的组合,可以方便你干一些重复的事情,提高你的效率。如果你曾经学习过其它编程语言,或者是 Windows 的批处理文件,那么你在学习 Shell Script 时应该会简单很多。不过没有经验也不要紧,让我们一起接下来的学习吧!
|
||||||
|
|
||||||
|
## Shell Script 文件的结构
|
||||||
|
|
||||||
|
在 Linux 上,Shell Script 一般的后缀名是 `.sh`。不过,你可以使用任何后缀(但是为了可读性最好不要这么做),也可以像可执行文件一样干脆不加任何后缀。
|
||||||
|
|
||||||
|
一个 Shell Script 的结构如下面所示:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
<这里可以写任意的命令>
|
||||||
|
<这里可以写任意的命令>
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
你可以在这里面写上许多行使用回车分隔的命令,这些命令会被按顺序执行。
|
||||||
|
|
||||||
|
Shell Script 的结构非常自由。其中,第一行被称为 `shebang`,以 `#!` 开头,可以指定运行这个程序的程序(即解释器)。常见的如 `/bin/bash` 就是我们正在讲的 Shell Script,还有 `/bin/sh` 也是一样(但是缺少部分功能)。Shebang 也可以不加,但是就不能直接用 `./你的sh文件` 去执行了。
|
||||||
|
|
||||||
|
> Shebang 的用处很多,可以指定一个文本文件的执行方式,可以使任意文本文件(例如 Python 和 Awk 脚本)具有可执行的能力,而 Windows 就只能靠后缀名区分。
|
||||||
|
|
||||||
|
## 执行 Shell Script
|
||||||
|
|
||||||
|
Shell Script 的执行也很简单:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash 你的sh文件
|
||||||
|
./你的sh文件
|
||||||
|
```
|
||||||
|
|
||||||
|
然后你的所写的命令会被一条一条按顺序执行下去。
|
||||||
|
|
||||||
|
> 在执行 Shell Script 的时候,你执行的所有命令用户都无法直接看到,只能看到每行命令的输出。
|
||||||
|
|
||||||
|
## 注释
|
||||||
|
|
||||||
|
在 Shell Script 中,我们可以使用 `#` 来编写注释。这一行从 `#` 开始到这行结尾的内容都会被忽略。例如:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 这是注释内容
|
||||||
|
|
||||||
|
ls # 这也是注释内容,前面的 ls 会被执行
|
||||||
|
```
|
||||||
|
|
||||||
|
> 为什么要编写注释?注释可以让其他人或者几个月后的你快速读懂你的 Shell Script 而不用一行一行理解。所有最好养成一个写注释的习惯 ~~(事实上很多程序员都不愿写注释)~~。
|
||||||
|
|
||||||
|
## 字符串
|
||||||
|
|
||||||
|
如果我们想要在 Bash 中定义一段文本,你可以直接输入,但是如果在文本中要出现分号这类的字符,那么我们就要使用引号了。
|
||||||
|
|
||||||
|
在 Bash 中,定义文本(字符串)有下面几种方式:
|
||||||
|
|
||||||
|
- 双引号 `"`
|
||||||
|
|
||||||
|
这个是最常用的一种方式。在双引号中,我们可以包含分号等字符,也可以正常包含各种变量。例如 `echo "test ${var}"` 会输出 `test 1`(假设 `var=1`)。
|
||||||
|
|
||||||
|
- 单引号 `'`
|
||||||
|
|
||||||
|
在单引号中,如果你尝试包含变量的话,你会发现变量会按照原样输出,不会被替换。例如 `echo 'test ${var}'` 会输出 `test ${var}`。
|
||||||
|
|
||||||
|
如果想要在字符串里再包含单双引号?别担心,我们可以使用 `\` 进行字符串“转义”,就是把 `\` 和它后面的一个字符一块看成一个特殊字符。需要转义的有 `$` 、单双引号和它本身(使用 `\\`)。
|
||||||
|
|
||||||
|
## 参数
|
||||||
|
|
||||||
|
另外,在 Shell Script 运行时可以向前面的 `cp` 等命令一样携带参数。
|
||||||
|
|
||||||
|
可以使用下面的方法获取:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$0 # 获取执行当前脚本的命令
|
||||||
|
$1 ~ $9 # 获取第 n 个参数(n 代表 $ 后的数字)
|
||||||
|
${10} # 同上,但是超过第 10 个参数后需要使用大括号
|
||||||
|
```
|
||||||
|
|
||||||
|
## 运算
|
||||||
|
|
||||||
|
在 Shell 中,我们如何让 Bash 进行运算呢?我们可以使用 `$[]` 表达式。例如:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "$[1+1]"
|
||||||
|
```
|
||||||
|
|
||||||
|
会输出 2
|
||||||
|
|
||||||
|
在运算中,我们同样可以使用变量。在运算中,变量通常不需要使用大括号。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
var=1
|
||||||
|
echo "$[$var+1]"
|
||||||
|
```
|
||||||
|
|
||||||
|
同样会输出 2
|
||||||
|
|
||||||
|
Bash 中括号支持常见的数学运算符号,也有一些其它的符号:
|
||||||
|
|
||||||
|
- `+` 加
|
||||||
|
- `-` 减
|
||||||
|
- `*` 乘
|
||||||
|
- `/` 除
|
||||||
|
- `%` 模运算,或者说取余
|
||||||
|
- `>` `>=` `<` `<=` `!=` 判断数字大小,满足返回 1,否则返回 0
|
||||||
|
- `&` 与符号,如果两个都不是 0 或者空,那么返回第一个不是 0(空)的数
|
||||||
|
- `|` 或符号,如果第一个不是 0 或者空,那么返回第一个,否则返回第二个
|
||||||
|
|
||||||
|
> 与和或符号的这种运算被称为“短路”,返回结果如果继续进行逻辑运算的话也可以当成 1 使用。
|
||||||
|
>
|
||||||
|
> Bash 中,中括号的数学运算本质上是 `expr` 命令。
|
||||||
|
|
||||||
|
## 显示进度
|
||||||
|
|
||||||
|
前面说了,你执行的所有命令用户都无法直接看到。那么我们如何让用户知道脚本进行到哪了呢?答案实际上很简单,就是 `echo`。用户是可以看到命令的输出的。
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "第一步"
|
||||||
|
echo "第二步"
|
||||||
|
echo "第三步"
|
||||||
|
echo "完成"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 等待
|
||||||
|
|
||||||
|
## 从终端输入内容
|
||||||
|
|
||||||
|
## 课后作业
|
||||||
|
|
||||||
|
Bash 和 Shell Script 本身其实并不是很难,但是却有着无穷多的可能性。我们学习使用 Shell Script 可以方便我们的学习与工作。
|
||||||
|
|
||||||
|
> 尝试在所有 Shell Script 中写上完整的注释吧!
|
||||||
|
|
||||||
|
1. 编写一个 `helloworld.sh`,可以输出 5 遍 `Hello, World!`。
|
||||||
|
2. 编写一个 `write.sh`,可以传入一个文件名参数,可以把 `Hello, World!` 写入到这个文件里。
|
||||||
|
3. 编写一个 `add.sh`,可以从终端输入两个数字,可以输出这个两个数字的和。
|
Loading…
Reference in New Issue