# 使用 bash 走向胜利

## 目标

* 启动 bash shell
* 设置工作目录
* 列出该目录中的文件
* 从 shell 启动 Python
* 打印 Python 程序的命令行参数

这是一个有趣的[来自麻省理工学院的终端游戏](http://web.mit.edu/mprat/Public/web/Terminus/Web/main.html)。

## 描述

UNIX shell（在我们的例子中是`bash`）是一种交互式领域特定语言，用于控制和监视 UNIX 操作系统，包括进程，设备，ram，cpu，磁盘等。它也是一种编程语言，尽管我们会主要用于移动文件，执行命令等。如果必须使用 Windows 机器，请安装 UNIX shell，使用 VMWare 安装 Linux，或启动 UNIX 盒子和 Amazon Web 服务。

您需要熟悉 UNIX 命令行，因为我们将使用命令行控制所有云计算设施。

当您第一次启动`Terminal.app`，或使用您拥有的任何 Linux 应用程序启动 shell 时，您将看到简单的美元提示或更复杂的内容，显示当前目录或当前机器等：

```bash
$ 
```

shell 只是一个像 Python 一样的交互式解释器：

```python
>>> print "hello"
hello
>>>
```

在 bash 中做同样的事情：

```bash
$ echo "hello"
hello
$
```

shell 有许多状态变量，其中一个是*当前工作目录*。 我们执行的大多数命令都是相对于此工作目录的。 您可以使用以下命令打印出当前工作目录：

```bash
$ pwd
/Users/parrt/github/msan501/notes
$ 
```

通过输入可能带参数的命令来执行命令并按回车后，您会收到提示。它为另一个命令准备好了。

任何以`/`开头的*路径*表示它是从磁盘目录体系的根开始的绝对路径。 （您可以在维基百科深入了解[路径](https://en.wikipedia.org/wiki/Path_(computing)#Unix_style)）。 所以其他任何东西都被认为相对于当前的工作目录。 例如，如果您当前的工作目录是`/Users/parrt/github/msan501`，那么`ls notes`将为您提供`/Users/parrt/github/msan501`下面的`notes`目录的目录列表。 这是一个有用的图表，显示了名为`view.py`的文件的完全限定路径名的成分：

<img src=img/path-names.png width=750>

最常见的事情之一是使用`cd`更改当前工作目录：

```bash
$ cd /Users/parrt/github/msan501
$ pwd
/Users/parrt/github/msan501
$ 
```

您可以请求该目录中的文件列表：

```bash
$ ls
LICENSE      README.md    data/        labs/        notes/       projects/
```

请注意，`~`是一个特殊字符，表示“用户的主目录”。Mac 上对于任何`YOURID`都是`/Users/YOURID`的。 对我来说是`/Users/parrt`。

磁盘上有很多程序。 您只需使用其名称作为命令行中的第一个元素即可启动它们。 例如，以下是我们如何启动 Python shell：

```bash
$ python
Python 2.7.12 |Anaconda 4.2.0 (x86_64)| (default, Jul  2 2016, 17:43:17) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
Anaconda is brought to you by Continuum Analytics.
Please check out: http://continuum.io/thanks and https://anaconda.org
>>> 
```

那当然给了我们一个新的提示符，`>>>`，这是 Python 用的。 我们可以通过按下 control-D（这意味着“文件末尾”）退出 Python。 当我们退出 Python 时，它将把我们带回 shell 和`$`提示符。

命令名称后面的任何内容都被视为该命令的参数。 例如，以下是获取特定目录的目录列表方式，即使我们当前不在该目录中：

```bash
$ ls /bin
[*          csh*        echo*       ksh*        mkdir*      rcp*        stty*       wait4path*
bash*       date*       ed*         launchctl*  mv*         rm*         sync*       zsh*
cat*        dd*         expr*       link*       pax*        rmdir*      tcsh*
chmod*      df*         hostname*   ln*         ps*         sh*         test*
cp*         domainname* kill*       ls*         pwd*        sleep*      unlink*
```

语法通常是:

```
command arg1 arg2 arg3
```

这类似于 Python 中的以下函数调用：

```
command(arg1, arg2, arg3)
```

另一个例子，这是我们执行特定的 Python 脚本而不是进入 Python 交互式模式的方式：

```bash
$ python myscript.py
... any output from the script ...
```

当然，我们经常希望将参数传递给 Python 脚本本身。 这些参数紧跟着提供给`python`命令的脚本名称。 例如，这是一个简单的脚本，它打印脚本的任何参数（让我们把它放到`args.py`）：

```python
import sys
print "args:", sys.argv[1]
```

我们这样运行脚本：
 
```bash
$ python args.py hi mom
args: ['args.py', 'hi', 'mom']
$ 
```