geekdoc-python-zh/docs/pythonland/64.md

276 lines
8.7 KiB
Markdown
Raw Permalink Normal View History

2024-03-03 22:54:39 +08:00
# 如何创建 Bash 脚本,带有示例代码
> 原文:[https://python.land/the-unix-shell/creating-bash-scripts](https://python.land/the-unix-shell/creating-bash-scripts)
使用 bash 脚本,您可以运行命令序列。它们防止你重复你自己,并允许你存储冗长乏味的输入命令以备后用。在本文中,您将学习如何创建 Bash 脚本。您还将学习如何读取参数、使用变量以及创建 for 循环来重复操作。
在开始创建脚本之前,确保您熟悉基本的 Linux 命令。
目录
* [创建一个 Bash 脚本](#Create_a_Bash_script "Create a Bash script")
* [Bash 变量](#Bash_variables "Bash variables")
* [Bash 脚本参数](#Bash_Script_arguments "Bash Script arguments")
* [Bash for loop](#Bash_for_loop "Bash for loop")
* 【Bash 脚本示例
* [启动 Bash 脚本](#Starting_a_Bash_script "Starting a Bash script")
* [Bash 条件编程](#Bash_conditional_programming "Bash conditional programming")
## 创建一个 Bash 脚本
命令行脚本以 shebang 开始she bang 是两个字符`#!`的序列。在这两个字符之后,你可以命名任何解释器和一串参数,就像这样:
```py
#!interpreter [optional arguments]
```
一个 shell 脚本通常基于最流行的 shell Bash因此它可以简单地变成:
```py
#!/bin/bash
```
有时你会看到这个:
```py
#!/usr/bin/env bash
```
使用`/usr/bin/env`时,提供的命令会在当前`$PATH`中搜索,而不是硬编码到`/bin/bash`位置。Bash 几乎总是出现在`/bin/bash`,所以第一种方法对我们来说很好。
然而,您可能想要使用这个技巧来创建一个可执行的 Python 脚本。Python 可以安装在任何地方,这取决于它的安装方式。我在`/usr/bin/`、`/bin`、`/usr/local/bin`都看过,就举几个吧。如果你运行的是虚拟环境,它可以在任何地方。所以搜索`$PATH`是一个好的选择,因为这将从虚拟环境中找到 Python 版本。
我们稍后将创建一个实际的 shell 脚本。但是首先,我们将看看变量和 for 循环,让事情更生动一些。
## Bash 变量
就像其他语言一样Bash 也有变量。Bash 中变量的一个奇特之处在于,您可以用美元符号访问它们,但却不用它来设置它们。为了澄清,这里有一个例子:
```py
myvar="Hello world"
echo $myvar
```
Bash 有许多为您自动设置的保留变量。下表列出了一些更有用的方法,但并不详尽:
| 可变的 | 功能 |
| --- | --- |
| $0 | 当前脚本的名称。 |
| $1 … $9 | 脚本的前 9 个参数。 |
| $# | 传递给脚本的参数数量。 |
| $@ | 提供给脚本的所有参数。 |
| $用户 | 运行脚本的用户的用户名。 |
| $主机名 | 运行脚本的机器的主机名。 |
| 美元秒 | 自脚本启动以来的秒数。 |
| $随机 | 每次被引用时返回一个不同的随机数。 |
| $行号 | 返回 Bash 脚本中的当前行号。 |
Bash 保留变量
## Bash 脚本参数
我们现在能够创建一个 shell 脚本,但是这个脚本将在您每次运行它时做同样的事情。我们可以通过使用论点让它变得更加有趣。
这里有个例子,叫它`arguments.sh`:
```py
#!/bin/bash
echo "Hello $1, from $0"
```
如果我们用一个参数运行它,结果如下:
```py
$ ./arguments.sh Weirdo
Hello Weirdo, from ./arguments.sh
```
Bash 所做的,是把你的整个命令分割开来,并把它分配给不太有想象力的变量`$0`、`$1`、`$2`等等。如您所见,我们命令的第一部分是脚本本身的名称。这可以派上用场,在下一节中可以看到。
### 创建一个安全网
在进入正题之前,我想教你一个重要的安全网。
一旦开始创建脚本,就不可避免地会出错。我们都是。脚本中一个非常常见的错误可能是灾难性的。这是未设置的变量。如果你不明白我的意思,只要继续读下去,一会儿就会明白了。
Thank you for reading my tutorials. I write these in my free time, and it requires a lot of time and effort. I use ads to keep writing these *free* articles, I hope you understand! **Support me by disabling your adblocker on my website** or, alternatively, **[buy me some coffee](https://www.buymeacoffee.com/pythonland)**. It's much appreciated and allows me to keep working on this site!
我们可以通过使用以下命令启动脚本来防止使用未设置的变量:
```py
set -u
```
仅此而已!从现在开始,当您进行替换时,您的脚本会将未设置的变量视为错误。
例如,此脚本将失败:
```py
#!/bin/bash
set -u
rm -rf /$my_directory
```
输出:
```py
$ ./test.sh
./test.sh: 3: ./test.sh: my_directory: parameter not set
```
那是因为我从来没有设置过`$my_directory`。没有`set -u`,它不会失败,而是忽略空变量,留给我们命令`rm -rf /`。我们都知道那是什么,对吧?如果由特权用户(比如`root`)执行,这个错误将会清除我的整个文件系统,而不是我想要删除的目录。
养成总是以`set -u`开始脚本的习惯。
## Bash for loop
一旦掌握了 Bash for-loops命令行(尤其是脚本)的用处就会成倍增加。尽管它们看起来很吓人,但其实并没有那么难。
### Bash for 循环的语法
循环的基本语法是:
```py
for VARIABLE in A LIST
do
command1
command2
commandN
done
```
## 【Bash 脚本示例
`A LIST`部分可以是任何东西:文件名、数字或字符串。不过,在大多数脚本中,它将是一个文件名列表,因为这是我们在 Bash 中经常使用的。现在我们知道了如何创建一个循环,让我们看看我们的第一个脚本:
```py
#!/bin/bash
echo "You can list numbers and text like this:"
for n in 1 2 3 four
do
echo "Number $n"
done
echo "Or specify a range of numbers:"
for n in {1..5}
do
echo "Number $n"
done
echo "Or use the output of another command:"
for f in $(ls)
do
echo $f
done
```
在上一个 for 循环中,我使用了表达式`$(ls)`。这会执行括号中的命令并替换结果。在这种情况下,`ls`被执行for 循环被输入了`ls`打印出的文件名。
## 启动 Bash 脚本
要启动这个脚本,我们可以做两件事。首先,我们可以运行它:
```py
$ bash loop.sh
```
我推荐的第二种方法是使文件可执行。操作系统将知道如何执行我们的文件,因为我们的 shebang 行在顶部!通过设置文件的“执行标志”可以使文件成为可执行文件,如下所示:
```py
$ chmod +x loop.sh
```
现在,您可以使用以下命令运行该脚本:
```py
$ ./loop.sh
```
在我的例子中,输出是:
```py
$ ./loop.sh
You can just list a bunch of numbers and text like this:
1
2
3
four
Or specify a range of numbers:
1
2
3
4
5
Or use the output of another command:
loop.sh
notes.txt
```
对您来说可能有所不同,这取决于运行脚本的目录中有哪些文件。
## Bash 条件编程
有时,您只想在特定条件为真时运行命令。为此,我们在 bash 中使用了`if… then… else…fi`构造。
### 检查 bash 脚本中的参数
我们可以使用条件编程来改进我们之前的例子`arguments.sh`,因为它包含了一个小问题。它期望在`$1`中有一个名字,但不检查它是否真的有名字。让我们来解决这个问题:
[https://crumb.sh/embed/fawGEMEUYGg](https://crumb.sh/embed/fawGEMEUYGg)
检查 Bash 脚本中的参数
如果这不起作用,下面是相同代码的静态版本:
```py
#!/bin/bash
if test -z "$1"
then
echo "Usage: $0 <Your name>"
else
echo "Hello $1, from $0"
fi
```
### bash 中的测试命令
用`test -z`我们可以检查变量的长度是否为零。如果是这种情况,我们打印一些友好的使用说明:
```py
$ ./arguments.sh
Usage: ./arguments.sh <Your name>
```
test 命令可以测试很多东西,所以它确实有助于条件编程。当你在命令行输入`man test`就可以看到完整的列表。没错,你不需要什么都用谷歌!使用手册页是成为命令行忍者的一部分!您会发现,几乎所有您可以在终端中做的事情都有一个手册页。毕竟,在过去,我们没有互联网来搜索一切…
下面是我们比较两个值以确定它们是否相同的另一个例子:
[https://crumb.sh/embed/3PAwdsNPFva](https://crumb.sh/embed/3PAwdsNPFva)
比较 Bash 中的两个值
下面是静态版本,以防不起作用:
```py
#!/bin/bash
for i in {1..10}
do
if test $i -eq 3
then
echo "I found the 3!"
else
echo "Not looking for the $i"
fi
done
```
该循环运行 10 次迭代,每次检查`$i`是否等于 3。你能预测产量吗
尽管`else`-部分是可选的,但您总是需要以`fi`结尾。