From f6f669febd05728c9cc0f808bb82d331210d4121 Mon Sep 17 00:00:00 2001 From: cxykevin Date: Tue, 3 Sep 2024 22:00:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90shellscript?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/SUMMARY.md | 2 +- src/linux_common_sense.md | 12 ++ src/shell_and_shell_script/learn_shell.md | 79 +++++++++- .../shell_script_basic.md | 139 ++++++++++++++++++ 4 files changed, 224 insertions(+), 8 deletions(-) create mode 100644 src/shell_and_shell_script/shell_script_basic.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 33f8d46..7aaa4ad 100755 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -24,7 +24,7 @@ - [学习Shell](./shell_and_shell_script/learn_shell.md) - [Job]() - [Vim编辑器](./shell_and_shell_script/vim_editor.md) - - [Shell Script基本语法]() + - [Shell Script基本语法](./shell_and_shell_script/shell_script_basic.md) - [条件判断语句]() - [循环]() - [函数]() diff --git a/src/linux_common_sense.md b/src/linux_common_sense.md index 9baf5dc..ec9dd01 100644 --- a/src/linux_common_sense.md +++ b/src/linux_common_sense.md @@ -34,6 +34,18 @@ Linux 中,每个文件夹下,都有两个特殊的目录,就是`.`和`..` ## 基本操作 +### `echo` 输出字符 + +`echo` 的本意是“回声”,因为 `echo` 命令就是把你给它的参数输出一遍。你说什么它就回什么,和回声一样。 + +```bash +echo 你想说的任何内容 +``` + +> echo 命令可以使用在内容前加上 `-e`,就是开启转义(就是把 `\` 和下一个字符看作一个字符),例如 `\n` 是换行,更多的转义内容可自行查找。 +> +> echo 是最简单的 Linux 命令了,但是在后面的用处会十分的大。 + ### `ls` 列出文件 `ls`,顾名思义,就是 list,列出当前目录下的文件,他的基本使用方法也很简单: diff --git a/src/shell_and_shell_script/learn_shell.md b/src/shell_and_shell_script/learn_shell.md index d3e19d2..a4dcaf0 100644 --- a/src/shell_and_shell_script/learn_shell.md +++ b/src/shell_and_shell_script/learn_shell.md @@ -46,15 +46,25 @@ command [options] [arguments] ## 变量 -Shell 中的变量分为环境变量和用户变量,环境变量是Shell启动时自动设置的变量,用户变量是用户自定义的变量。 +Shell 中的变量分为局部变量、系统变量和全局变量,系统环境变量是 Shell 启动时自动设置的变量,局部变量和全局变量是用户自定义的变量。 -用户变量可以通过 `export` 命令设置为临时环境变量,例如: +### 创建(定义)变量 + +我们可以用 `=` 创建一个局部变量,例如: + +```bash +GREET="Hello, World!" +``` + +> 这里注意等号的两边都不要有空格 + +变量可以通过 `export` 命令设置为全局变量,例如: ```bash export GREET="Hello, World!" ``` -然后我们在这个 Shell 里启动一个新的 Shell,仍然可以在环境中找到这个变量。 +然后我们在这个 Shell 里启动一个新的 Shell,仍然可以在环境中找到这个全局变量。而一般变量就找不到了。 ```bash bash -c 'echo $GREET' @@ -62,12 +72,57 @@ bash -c 'echo $GREET' > `export` 声明的变量只在当前环境下有效,如果你开启了个新的终端或者重启,那么这个环境就无效了 -用户变量可以通过 `declare` 命令声明,例如: +变量也可以通过 `declare` 命令声明,例如: ```bash 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 @@ -77,9 +132,13 @@ echo $USER_GREET > 当变量的前后有别的内容紧挨着,那么只能使用 `${}`。 -## 特殊的环境变量 +如果使用的变量不存在,那么程序不会报错,会默默的把这个变量 **替换为空值**,这点需要十分注意。 -Shell 中有一些特殊的环境变量,它们在 Shell 启动时自动设置,例如: +> 之前,有个软件的卸载用的 Shell Script 有一个 bug,会运行 `rm -rf $(INSTALL_PATH)/*`,但是这里的 `INSTALL_PATH` 变量可能会未定义,最终导致了清除了整个根目录。 + +### 系统变量 + +Shell 中有一些系统变量,它们在 Shell 启动时自动设置,例如: - `$HOME`:当前用户的主目录。 - `$PATH`:可执行文件的搜索路径。 @@ -87,10 +146,16 @@ Shell 中有一些特殊的环境变量,它们在 Shell 启动时自动设置 - `$PWD`:当前工作目录。 - `$USER`:当前用户的用户名。 -其中最重要也是最常用的就是 PATH,它决定了Shell在执行命令时搜索可执行文件的路径。当我们发现明明安装了某个软件但是找不到可执行文件的时候应该首先检查 PATH 的设置。如果你熟悉 Windows,你会发现 Windows 的 PATH 是一串由分号分隔的路径。而 Linux 下的路径使用的是 `:` 冒号分隔。 +其中最重要也是最常用的就是 PATH,它决定了 Shell 在执行命令时搜索可执行文件的路径。当我们发现明明安装了某个软件但是找不到可执行文件的时候应该首先检查 PATH 的设置。如果你熟悉 Windows,你会发现 Windows 的 PATH 是一串由分号分隔的路径。而 Linux 下的路径使用的是 `:` 冒号分隔。 > 在 Windows 中的 PATH 中有一条路径是 `.` 就是当前目录,而 Linux 中默认是不会搜索当前目录的。如果你在当前目录有一个 `run.sh`,那么你必须要使用 `./run.sh` 才能执行。 +另外还有以下几个特殊的系统变量: + +- `$?`:上一个运行的程序的返回值(一个数字,通常 0 表示成功,其它数字表示错误,不同程序不同错误的返回值一般不同) +- `$0`:启动当前终端程序或者 ShellScript 的命令,如 `/bin/bash` +- `$#`:启动当前终端程序或者 ShellScript 的参数个数。 + ## 管道 Shell 中的管道是链接两个命令的方式,管道遵守下面的格式。 diff --git a/src/shell_and_shell_script/shell_script_basic.md b/src/shell_and_shell_script/shell_script_basic.md new file mode 100644 index 0000000..1444407 --- /dev/null +++ b/src/shell_and_shell_script/shell_script_basic.md @@ -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`,可以从终端输入两个数字,可以输出这个两个数字的和。