Bash是(从今天起)你将接触到的大多数系统上事实上的shell。Linux、macOS,以及Windows 10上的WSL。
有一些历史原因使Bash成为世界上最受欢迎的shell。早在1989年,当它首次发布时,技术世界是非常不同的。当时,UNIX世界中的大多数软件都是闭源的。Unix本身也是专有和封闭的。
要使用一个UNIX系统,你必须使用一个shell。
当时最流行的shell是闭源和专有的,你必须付钱才能使用它。它是Bourne shell,在/bin/sh 命令下可用。它被称为 "Bourne "是因为它的创造者是Steve Bourne。
在那些年里,Richard Stallman与GNU项目(以及后来的Linux)一起,即将彻底改变一切,开始了开源革命。GNU项目需要一个外壳,在自由软件基金会的帮助下,Bash诞生了。Bash在很大程度上受到Bourne Shell的启发,它的意思是Bourne-again shell,它是GNU项目的一个关键要素,也可能是它最成功的软件之一,我们今天仍然在使用。
Bash可以运行所有为sh 编写的脚本,这是它被采用的一个强制性特征,而且从早期开始,它还引入了许多其他特征,为用户提供了更好的体验。从早期开始,Bash获得了很多改进。本教程描述了你可以用它做的最流行和最有用的事情。
Bash的第一个步骤
由于Bash是许多系统中的默认shell,你只需要启动一个bash shell即可
- 登录到系统中,如果它是一个服务器的话
- 打开你的终端,如果是你的电脑的话
请看我的macOS终端指南,了解更多关于在Mac上使用终端的信息。
一旦你启动它,你应该看到一个提示(通常以$ 结尾)。
你怎么知道shell正在运行bash?试着输入help ,然后按回车键。

看到了吗?我们刚刚告诉Bash去执行help 命令。这个命令反过来会显示你正在运行的Bash的版本和你可以使用的命令列表。
警告:看到我这里的版本了吗?它是3.2.57。这是macOS中默认的Bash版本,由于许可问题,它不包括更高的版本。这个Bash版本是2014年的。使用Homebrew安装最新的Bash 5.x,输入
brew install bash。
更多的时候,你不会使用bash帮助中列出的任何命令,除非你正在创建shell脚本或高级的东西。
99%的日常shell使用是浏览文件夹和执行程序,如ls,cd 和其他公共UNIX工具。
浏览文件系统
要在文件系统中导航,你将使用ls 命令。它在/bin/ls 中可用,由于Bash在其路径列表中有/bin 文件夹,你可以直接输入ls 来使用它。
ls 列出当前文件夹中的文件。你通常从你的主文件夹开始,这取决于系统,但在macOS上是在 。我的主文件夹是在 。这与Bash无关,它更像是UNIX文件系统的东西,但参数是重叠的,如果你从来没有使用过shell,知道这一点很好。/Users /Users/flavio

要导航到其他文件夹,你可以使用cd 命令,后面跟上你要移动的文件夹的名字。
cd .. 就会回到父文件夹。
根据你的Bash配置,你会看到你当前的文件夹显示在提示($ 符号)之前。也可能没有,但你可以通过输入pwd ,然后按回车键来知道你在哪里。
pwd指工作 目录的路径名
命令行编辑
当你在shell中编写命令时,注意你可以用方向键左右移动。这是一个shell功能。你可以在你的命令周围移动,按退格键和纠正命令。按enter 键告诉shell去,让系统执行命令。
这是正常的、被接受的行为,但可能让早期的UNIX用户 "惊叹 "的东西。
键盘组合可以让你快速编辑,而不需要伸手去按方向键。
ctrl+d删除当前选定的字符ctrl+f转到右边的字符ctrl+b转到左边的字符
自动补全
在文件系统中移动时,Bash的一个很好的功能是自动完成。试着输入cd Doc ,并按下tab ,使Bash自动完成cd Documents 。如果这些第一个字符有多个选择,Bash将返回你的列表,所以你可以再输入几个字符来帮助它消除歧义,并再次按下tab ,完成。

shell可以自动完成文件名,但也可以自动完成命令名。
外壳命令
使用shell,我们可以运行系统中可用的命令。我们可以在命令前加上完整的路径(例如,/bin/ls 来列出一个文件夹中的文件),但是shell有路径的概念,所以我们可以直接输入ls ,它就知道大多数命令在哪里可以找到(我们可以通过配置将文件夹添加到这个路径中)。
命令接受参数。例如,ls /bin 将列出/bin 文件夹中的所有文件。
参数的前缀是破折号- ,如ls -a ,它告诉ls ,也显示隐藏的文件。按照惯例,隐藏文件是以点开头的文件(和文件夹)(.)。
常见的shell命令
在任何系统上都有很多预装的命令,它们的差异很大,这取决于你所运行的是Linux/macOS还是Linux发行版。
然而,让我们对你可以运行的最常见的shell命令做一个简要的总结。这些不是由shell本身提供的,而是你可以通过shell调用的命令行命令。
当你遇到问题时,比如你不知道某个命令是做什么的,或者你不知道如何使用它,请使用man 。它可以让你得到我将列出的所有命令的帮助,还有更多。例如,运行man ls 。
这些是文件系统的命令。
ls列出文件cd改变文件夹rm删除一个文件或文件夹mv将一个文件移到另一个文件夹,或改变一个文件名cp复制一个文件pwd显示当前工作目录mkdir创建一个文件夹
Unix文件系统中的每个文件都有权限。chmod ,允许你改变这些权限(现在不说了),chown ,允许你改变文件所有者。
cat,tail 和grep 是处理文件的两个超级有用的命令。
pico,nano,vim 和emacs 是通常安装的编辑器。
whereis 在macOS上,显示了一个命令在系统中的位置。
当然,还有更多的命令,但这些是你可能更经常碰到的几个。
执行命令
ls 和 是命令,正如我提到的,它们在 文件夹中找到。你可以执行任何文件,只要它是一个可执行文件,只要输入它的完整路径,例如 。命令不需要在 文件夹中,你可以使用 路径指示器来运行在你当前文件夹中的可执行文件。cd /bin /bin/pwd /bin ./
例如,如果你在你的/Users/flavio/scripts 文件夹里有一个runme 文件,你可以运行
然后再运行./runme 来运行它。
或者你可以从Bash运行/Users/flavio/scripts/runme ,无论你的当前文件夹在哪里。
工作
每当你运行一个命令时,如果它是一个长期运行的程序,你的shell将完全被该命令所占有。你可以使用ctrl-C 删除该命令。
在任何时候,你都可以运行jobs 来查看你正在运行的作业,以及它们的状态。
$ jobs
Job Group State Command
1 72292 stopped ftp
另一个有用的命令是ps ,它列出了运行中的进程。
$ ps
PID TTY TIME CMD
19808 ttys000 0:00.56 /usr/local/bin/fish -l
65183 ttys001 0:04.34 -fish
72292 ttys001 0:00.01 ftp
top 它显示了进程和它们在你的系统上所消耗的资源。
一个工作或进程可以用kill <PID> 。
命令历史
按up 箭头键将显示你所输入的命令的历史。同样,这是一个shell的功能。按down 方向键可以让你在时间上来回浏览,看看你之前输入了什么命令,按enter 可以让你再次运行该命令。
这是对命令历史的快速访问。运行history 命令将显示在shell中输入的所有命令。

当你开始输入一条命令时, Bash可以通过参考历史上以前输入的命令来自动完成它。按esc ,然后再按tab ,试试吧。
说实话,我觉得Fish shell实现这个功能要好得多,也更容易。
设置你的默认shell
除了Bash之外,还有很多其他的shell。你有Fish, ZSH, TCSH, 和其他一些。系统中的任何用户都可以选择自己的shell。
你可以通过运行chsh -s chsh -s /bin/bash 命令来设置你的默认登录shell。你几乎不需要这样做, 除非它以前被改变过, 比如说用Fish:
chsh -s /usr/local/bin/fish
定制Bash
我曾指出,你可能(也可能不)在Bash提示符中看到你的当前工作目录。这是在哪里决定的?在Bash的配置中!
这里有一点混乱,因为Bash在不同的情况下使用不同的配置文件,而且它还会读取多个配置文件。
让我们给这个混乱的局面一些秩序。首先,Bash是否被初始化为login shell有很大区别。我们所说的login shell是指系统没有运行GUI(图形用户界面),你通过shell登录到系统中。例如,服务器就是这种情况。
在这种情况下,Bash加载这个配置文件。
/etc/profile
然后在用户的主文件夹中寻找这些文件,按照顺序,执行它找到的第一个文件。
~/.bash_profile
~/.bash_login
~/.profile
were~ 表示你的主文件夹(它由Bash自动翻译)
这意味着如果有一个.bash_profile ,~/.bash_login 和~/.profile 永远不会被运行,除非在.bash_profile 中明确执行。
如果Bash不是一个登录的shell,而是像我在macOS中那样运行,例如,作为一个普通的应用程序,那么配置文件就会改变。Bash首先加载/etc/bash.bashrc ,然后是~/.bashrc 。
环境变量
有时你的程序会使用环境变量。那些是你可以在程序之外设置的值,并改变程序本身的执行。例如,一个API密钥。或者一个文件的名称。
你可以使用以下语法来设置环境变量
VARIABLE_NAME=variable_value
该值可以包含空白,通过使用引号
VARIABLE_NAME="variable value"
bash脚本可以使用这个值,在前面加上一个美元符号:$VARIABLE_NAME 。
此外,其他编程语言的命令也可以使用环境变量,例如这里是如何用Node.js读取环境变量的。
系统为你设置了一些环境变量,例如
$HOME你的主文件夹$LOGNAME你的用户名$SHELL你的默认shell的路径$PATHshell寻找命令的路径
你可以通过在它们前面加上echo 来检查它们的值。
echo $LOGNAME # flavio
echo $HOME # /Users/flavio
一个特殊的环境变量:$PATH
我提到了$PATH这个变量。这是一个文件夹列表,当你输入一个命令时,shell会在其中查找。文件夹之间用冒号: ,它们是按顺序写的--Bash会进入第一个文件夹,搜索你要的命令,如果找到了就运行它。否则就会进入下一个文件夹,以此类推。
我目前的路径是。
bash-5.0$ echo $PATH
/usr/local/bin:/usr/bin: /bin:/usr/sbin: /sbin:/usr/local/go/bin
你通常会在~/.bashrc 文件中通过预加或追加项目来编辑它。
PATH = "$PATH:/Users/flavio/bin"
别名
使用别名,我们可以为常用命令设置快捷方式。例如,你可以给一个复杂的参数组合起一个快速的名字。
你可以使用以下语法来定义别名
如果命令中有空格,则使用引号。
alias <alias>="<command>"
我经常添加到我的系统中的一个别名是ll 。
你通常在你的~/.bashrc 文件中定义别名。
如果你的命令中有变量,请小心使用引号:使用双引号,变量在定义时被解决,使用单引号,则在调用时解决。这两个是不同的。
alias lsthis="ls $PWD"
alias lscurrent='ls $PWD'
$PWD指的是当前shell所处的文件夹。如果你现在浏览到一个新的文件夹,lscurrent 列出新文件夹中的文件,lsthis 仍然列出你定义别名时所在的文件夹中的文件。
高级命令行功能
通配符
ls 和许多其他的命令可以很好地利用通配符。你可以列出所有以image开头的文件。
或所有以image结尾的文件。
或名称中含有image的所有文件。
重定向输出和标准错误错误
默认情况下,在shell中启动的命令会把输出和错误都打印到shell中。这可能不是你想要的。你可以决定把输出写到一个文件中。
实际上,是写到一个/不同的文件/,因为在Unix中,甚至屏幕也被认为是一个文件。特别是。
0识别标准输入1识别标准输出2识别标准错误
你可以将标准输出重定向到一个文件,方法是在一个命令后面加上1> ,然后再加上一个文件名。
使用同样的技术,你可以使用2> 来重定向标准错误。
有一个快捷键> ,用来表示1> ,因为这个词用得比较多。
例子。
ls 1> list.txt 2> error.txt
ls > list.txt 2> error.txt
另一个快捷方式,&> ,将/both/标准输出和标准错误重定向到一个文件。
另一个经常使用的是使用2>&1 ,将标准错误重定向到标准输出。
在后台运行一个命令
你可以告诉Bash在后台运行一个程序,而不对shell进行控制,方法是在它后面加上& 。
top是一个列出正在运行的进程的命令,按照最耗费资源的顺序排列。
通常会控制shell的程序现在被启动了,但似乎什么也没有发生。你可以通过输入fg (又称前台)使它重新成为焦点,但现在我们进入了进程和工作的领域,这本身就是一个很大的话题,但还是要快速浏览一下。
当一个命令正在运行时,你可以使用ctrl-Z 来暂停它,把它带到后台。shell又回到了前台,你现在可以运行bg ,以移动恢复执行之前暂停的工作。
当你准备回去的时候,运行fg ,将该程序带回前台。
你可以使用ps ,看到所有正在运行的进程,列表中显示所有的进程pid 号。使用暂停的进程pid ,你可以把一个特定的命令带到前台,例如fg 72292 。对bg 也是如此。
排列命令
你可以指示Bash在另一个命令结束后立即运行一个命令,方法是用分号把它们分开。
你可以重复这个动作来排查同一行中的多个命令.
输出重定向
一个程序可以使用< 操作符从任何文件接收输入,并使用> 操作符将输出保存到一个文件中。
echo hello > result.txt
wc < result.txt
wc 是一个将其收到的字数作为输入进行计数的命令。
管子
使用管道,任何命令的输出都可以作为第二个命令的输入。使用| 操作符将两者结合起来。在这个例子中,wc 从echo hello 的输出中获得输入。
分组命令
使用&& ,用 "和 "来组合两个命令。如果第一个命令的执行没有问题,就运行第二个,以此类推。
使用|| ,用 "或 "来组合两个命令。如果第一条命令的执行没有问题,第二条就不运行。
! 否定了下一个逻辑操作。
$ echo hello && echo test
hello
test
$ echo hello || echo test
hello
$ ! echo hello || echo test
hello
test
你可以使用括号来组合表达式以避免混淆,也可以改变优先级。
$ ! (echo hello) || (echo test)
hello
test
$ ! (echo hello || echo test)
hello
壳的编程
像Bash这样的shell的最大特点之一是它能够用它来创建程序,基本上是通过自动执行命令来实现的。
我将很快写一个关于Bash脚本的单独指南,它将与本教程分开,因为这个主题确实比我想在这个Bash入门指南中添加的内容更深入。
简单介绍一下:脚本是一个文本文件,以一行开始,表明它是一个shell脚本(以及它需要什么shell),然后是一个命令列表,每行一个。例子。
你可以把这个文件保存为myscript ,然后用chmod +x myscript ,使其可以执行,用./myscript (./ ,意思是 "当前文件夹")运行它。
Shell脚本不在这篇文章的范围内,但我想让你知道这一点。脚本可以有控制结构和许多其他很酷的东西。
这种脚本策略同样适用于其他shell,比如Zsh。