课程链接在此
作为计算机科学家,我们知道计算机很擅长执行重复性的任务。 然而,我们往往忘记了,这个特长不仅适用于计算机在执行我们的程序时进行计算,还适用于我们对计算机的使用。我们手头有大量的工具,这些工具使我们在处理任何与计算机相关的问题时能够更有效率地解决更复杂的问题。 然而,许多人只利用了这些工具的一小部分; 我们只知道一些死记硬背的魔咒,当我们陷入困境时,就盲目地从互联网上复制粘贴命令。
这门课程试图解决这个问题。
我们想教你如何充分利用你知道的工具,向你展示可以添加到你的工具箱中的新工具,并希望激起你对自己探索(或者构建)更多工具的兴趣。我们认为这是大多数计算机科学课程缺失的一个学期。
这门课由11节1小时的讲座组成,每个讲座都围绕一个特定的主题。课程在很大程度上是独立的,不过随着学期的进行我们会假设你们已经熟悉了之前课程的内容。
我们试图在11节1小时的课程中涵盖很多内容,所以课程内容相当密集。为了让你有时间按照自己的节奏熟悉课程内容,每节课都包括一组练习,指导你理解课程要点。
由于我们所拥有的时间有限,我们不可能像一个完整的类那样详细地介绍所有的工具。在可能的情况下,我们将尝试为您提供进一步挖掘工具或主题的资源。
现在的计算机有各种各样的接口来给它们下达命令;神奇的的图形用户界面,语音界面,甚至AR和VR无处不在。这些功能在80%的情况下都很好用,但它们通常从根本上限制了你所能做的事情——你不能按一个不存在的按钮,或者发出一个没有被编程的语音命令。为了充分利用计算机提供的工具,我们必须走老路,使用文本界面:Shell。
你可以接触到的几乎所有平台都有某种形式的shell,其中许多平台有多种shell供您选择。虽然它们在细节上可能有所不同,但它们的核心都大致相同:它们允许你以半结构化的方式运行程序、向它们提供输入并检查它们的输出。
在这堂课中,我们将再次探究Bourne SHell,或者简称bash。这是使用最广泛的shell之一,它的语法和你在许多其他shell中看到的类似。要打开shell提示符(可以在其中键入命令),首先需要一个终端。你的设备可能附带安装了一个,或者您可以相当容易地安装一个。
当你启动终端时,你将看到一个提示符,通常看起来像这样:
missing:~$
这是到shell的主要文本接口。它告诉你你正在missing
机器上,你“当前的工作目录”或当前所在的位置是~
(“home”的缩写)。$
告诉你你不是根用户(稍后将详细介绍)。在这个提示符下,您可以键入一个命令,然后shell将解释该命令。最基本的命令是执行程序:
missing:~$ date
Fri 10 Jan 2020 11:49:31 AM EST
missing:~$
这里,我们执行了date
程序,它打印当前日期和时间(可能并不令人惊讶)。然后shell要求我们执行另一个命令。我们也可以执行带参数的命令:
missing:~$ echo hello
hello
在本例中,我们告诉shell使用参数hello
来执行程序echo
。echo
程序只输出它的参数。shell通过空格分割命令来解析该命令,然后运行由第一个单词指示的程序,并提供随后的每个单词作为该程序可以访问的参数。如果你想提供一个包含空格或其他特殊字符的参数(例如,一个名为“My Photos”的目录),你可以用'
或"
("My Photos"
)引用参数,或者用\
(My\ Photos
)转义相关字符。
但是shell怎么知道如何找到date
或echo
程序呢?shell是一种编程环境,就像Python或Ruby一样,因此它有变量、条件、循环和函数(下一讲!)。当你在shell中运行命令时,实际上是在编写shell所解释的一小段代码。如果shell被要求执行一个与它的某个编程关键字不匹配的命令,它会查询一个名为$PATH
的环境变量,它列出了当shell被给出命令时应该搜索的程序目录:
missing:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
missing:~$ which echo
/bin/echo
missing:~$ /bin/echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
当我们运行echo
命令时,shell会看到它应该执行echo
程序,然后在$PATH
中搜索由:
分隔得到的目录列表,寻找同名的文件。当它找到它时,它运行它(假设文件是可执行的;稍后会详细介绍)。我们可以使用which
程序来确定给定程序名执行的是哪个文件。我们也可以通过给出我们想要执行的文件的路径来完全绕过$PATH。
shell中的路径是一个分隔的目录列表;在Linux和macOS上用/
分隔,在Windows上用\
分隔。在Linux和macOS中,路径/
是文件系统的“根目录”,所有的目录和文件都位于该目录下,而在Windows中,每个磁盘分区都有一个根目录(例如,C:\
)。我们通常假设你在课程中使用的是Linux文件系统。以/
开头的路径称为绝对路径。任何其他路径都是相对路径。相对路径是相对于当前工作目录的路径,我们可以使用pwd
命令看到它,并使用cd
命令更改它。在一个路径中,.
表示当前路径,..
是上一层路径:
missing:~$ pwd
/home/missing
missing:~$ cd /home
missing:/home$ pwd
/home
missing:/home$ cd ..
missing:/$ pwd
/
missing:/$ cd ./home
missing:/home$ pwd
/home
missing:/home$ cd missing
missing:~$ pwd
/home/missing
missing:~$ ../../bin/echo hello
hello
注意,我们的shell提示让我们知道当前的工作目录是什么。你可以配置提示符以显示各种有用的信息,我们将在后面的讲座中介绍这些信息。
一般来说,当我们运行一个程序时,它将在当前目录中操作,除非我们告诉它另外的情况。例如,它通常会在那里搜索文件,并在需要时在那里创建新文件。
要查看在给定的目录中有什么,可以使用ls
命令:
missing:~$ ls
missing:~$ cd ..
missing:/home$ ls
missing
missing:/home$ cd ..
missing:/$ ls
bin
boot
dev
etc
home
...
除非将目录作为其第一个参数给出,否则ls
将打印当前目录的内容。大多数命令接受以-
开头的标志和选项(带值的标志)来修改它们的行为。通常,运行带有-h
或--help
标志的程序将打印一些帮助文本,告诉你可用的标志和选项。例如,ls--help
告诉我们:
-l use a long listing format
missing:~$ ls -l /home
drwxr-xr-x 1 missing users 4096 Jun 15 2019 missing
这为我们提供了关于每个文件或目录的更多信息。首先,该行开头的d
告诉我们missing
是一个目录。然后跟随三个字符的三个组合(rwx
)。它们表明文件的所有者(missing
)、所属组(users
)和其他人分别对相关项拥有哪些权限。-
表示给定的主体没有给定的权限。上面,只有所有者可以修改(w
)missing
目录(即,添加或删除其中的文件)。要输入一个目录,用户必须对该目录(及其父目录)具有“search”(由“execute”:x
表示)权限。要列出目录的内容,用户必须具有该目录的读(r
)权限。对于文件,权限与您所期望的一样。请注意,/bin
中的几乎所有文件都对最后一组“everyone else”设置了x
权限,因此任何人都可以执行这些程序。
目前需要了解的其他一些方便的程序有mv
(重命名或移动文件)、cp
(复制文件)和mkdir
(创建新目录)。
如果您想了解更多关于程序的参数、输入、输出或者它一般是如何工作的信息,请尝试使用man
程序。它接受一个程序的名称作为参数,并显示它的手册页。按q
退出。
missing:~$ man ls
在shell中,程序有两个主要的“流(streams)”相关联:它们的输入流和输出流。当程序试图读取输入时,它从输入流中读取,当它打印东西时,它将打印到它的输出流中。通常,程序的输入和输出都是终端。也就是说,键盘作为输入,屏幕作为输出。然而,我们也可以重新连接那些流!
最简单的重定向形式是<
文件和>
文件。它们可以让你分别将程序的输入流和输出流重新连接到一个文件:
missing:~$ echo hello > hello.txt
missing:~$ cat hello.txt
hello
missing:~$ cat < hello.txt
hello
missing:~$ cat < hello.txt > hello2.txt
missing:~$ cat hello2.txt
hello
在上面的例子中,cat
是一个concat
enates文件的程序。当给出文件名作为参数时,它将按顺序将每个文件的内容打印到其输出流中。但是当没有给cat
任何参数时,它会将输入流中的内容打印到输出流中(就像上面的第三个示例一样)。
你也可以使用>>
来追加文件。这种输入/输出重定向的真正闪光点在于*管道(pipes)*的使用。|
操作符可以让你“链接”程序,这样一个程序的输出就是另一个程序的输入:
missing:~$ ls -l / | tail -n1
drwxr-xr-x 1 root root 4096 Jun 20 2019 var
missing:~$ curl --head --silent google.com | grep --ignore-case content-length | cut --delimiter=' ' -f2
219
关于如何利用管道,我们将在data wrangling这一讲中详细介绍。
在大多数类unix系统中,有一个特殊的用户:“root”用户。您可能在上面的文件清单中看到过它。根用户高于(几乎)所有访问限制,可以创建、读取、更新和删除系统中的任何文件。不过,你通常不会以root用户登录系统,因为它很容易意外破坏某些东西。相反,你将使用sudo
命令。顾名思义,它允许你以su(“super user”或“root”的缩写)的身份“do”一些事情。当您得到拒绝权限错误时,通常是因为你需要作为根用户执行某些操作。但首先要确保你真的想这样做!
要想对挂载在/sys
下的sysfs
文件系统进行写操作,你必须是根用户。Sysfs
将许多内核参数公开为文件,这样你就可以在不使用专门工具的情况下轻松地动态地重新配置内核。注意,sysfs
在Windows或macOS上不存在。
例如,你笔记本电脑屏幕的亮度是通过一个名为brightness
的文件来显示的
/sys/class/backlight
通过在该文件中写入一个值,我们可以改变屏幕亮度。你的第一反应可能是:
$ sudo find -L /sys/class/backlight -maxdepth 2 -name '*brightness*'
/sys/class/backlight/thinkpad_screen/brightness
$ cd /sys/class/backlight/thinkpad_screen
$ sudo echo 3 > brightness
An error occurred while redirecting file 'brightness'
open: Permission denied
这个错误可能会让人感到意外。毕竟,我们使用sudo
运行命令!这对于了解shell是很重要的。像|
、>
和<
这样的操作是由shell来完成的,而不是由单独的程序来完成。echo
和它的同类不知道|
。它们只是读取输入,写入输出,不管输入是什么。在上面的例子中,shell(就像用户你一样进行身份验证)试图打开亮度文件进行写入,然后将其设置为sudo echo
的输出,但由于shell不是以root用户运行,因此无法这样做。利用这些知识,我们可以解决问题:
$ echo 3 | sudo tee brightness
由于tee
程序是打开/sys
文件进行写入的程序,并且它是作为root
用户运行的,因此所有权限都是有效的。你可以通过/sys
控制各种有趣和有用的东西,例如各种系统led的状态(你的路径可能不同):
$ echo 1 | sudo tee /sys/class/leds/input6::scrolllock/brightness
至此,你已经对shell有了足够的了解,可以完成基本的任务。你应该能够四处导航,找到感兴趣的文件,并使用大多数程序的基本功能。在下一讲中,我们将讨论如何使用shell和许多方便的命令行程序执行和自动化更复杂的任务。
本教程的所有课程都有一系列的练习。有些会给你一个具体的任务,而有些则是开放式的,比如“尝试使用X和Y程序”。我们强烈建议您尝试一下。
1.对于本课程,您需要使用像Bash或ZSH这样的Unix shell。如果你使用的是Linux或macOS,你不需要做任何特别的事情。如果你在Windows上,你需要确保你没有运行cmd.exe或PowerShell;您可以使用Windows子系统或Linux虚拟机来使用unix风格的命令行工具。要确保运行的是适当的shell,可以尝试使用echo $ shell
命令。如果它说的是/bin/bash
或/usr/bin/zsh
,这意味着你正在运行正确的程序。
2.在/tmp
下创建一个名为missing
的新目录。
hmt@missing:/$ ls
bin cdrom etc lib lib64 lost+found mnt proc run snap sys usr
boot dev home lib32 libx32 media opt root sbin srv tmp var
hmt@missing:/$ cd tmp
hmt@missing:/tmp$ mkdir missing
3.查看touch
程序。man
程序是你的朋友。
hmt@missing:/tmp$ man touch
The touch command is a standard command used in UNIX/Linux operating system which is used to create, change and modify timestamps of a file. Basically, there are two different commands to create a file in the Linux system which is as follows:
- cat command: It is used to create the file with content.
- touch command: It is used to create a file without any content. The file created using touch command is empty. This command can be used when the user doesn’t have data to store at the time of file creation.
4.使用touch
程序在missing
下创建一个名为semester
的新文件。
hmt@missing:/tmp$ cd missing
hmt@missing:/tmp/missing$ touch semester
5.将以下代码一行一行地写入该文件:
#!/bin/sh
curl --head --silent https://missing.csail.mit.edu
第一行可能很难理解。要知道在Bash中以#
开头的是一条注释,并且!
即使在双引号(")字符串中也有特殊的含义。Bash对待单引号字符串(')则不同:在本例中,它们将发挥作用。有关更多信息,请参阅Bash引用手册页。
hmt@missing:/tmp/missing$ echo '#!/bin/sh' > semester
hmt@missing:/tmp/missing$ echo curl --head --silent https://missing.csail.mit.edu >> semester
Enclosing characters in single quotes (‘'’) preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
Enclosing characters in double quotes (‘"’) preserves the literal value of all characters within the quotes, with the exception of ‘$’, ‘`’, ‘\’, and, when history expansion is enabled, ‘!’.
6.尝试执行该文件,即在shell中输入脚本的路径(./semester
)并按enter键。通过查看ls
的输出(提示:查看文件的权限位)来理解为什么它不能工作。
hmt@missing:/tmp/missing$ ./semester
bash: ./semester: 权限不够
hmt@missing:/tmp/missing$ ll
总用量 12
drwxrwxr-x 2 hmt hmt 4096 5月 25 21:43 ./
drwxrwxrwt 25 root root 4096 5月 25 21:43 ../
-rw-rw-r-- 1 hmt hmt 61 5月 25 21:43 semester
没有x
执行权限
7.通过显式启动sh
解释器来运行该命令,并将文件semester
作为第一个参数,即sh semester
。为什么这个行得通,而./semester
不行?
hmt@missing:/tmp/missing$ sh semester
HTTP/2 200
server: GitHub.com
content-type: text/html; charset=utf-8
last-modified: Sat, 14 May 2022 10:50:11 GMT
access-control-allow-origin: *
etag: "627f8963-1f37"
expires: Sat, 21 May 2022 14:09:24 GMT
cache-control: max-age=600
x-proxy-cache: MISS
x-github-request-id: 92D6:1B36:62E11:9C3B7:6288F03C
accept-ranges: bytes
date: Sat, 21 May 2022 14:40:20 GMT
via: 1.1 varnish
age: 0
x-served-by: cache-hkg17920-HKG
x-cache: MISS
x-cache-hits: 0
x-timer: S1653144020.915118,VS0,VE267
vary: Accept-Encoding
x-fastly-request-id: 4bbe8f600c733755da30e391ddb925721c5ba1a9
content-length: 7991
8.查看chmod
程序(例如使用man chmod
)。
hmt@missing:/tmp/missing$ man chmod
This command modifies Linux file permissions
9.使用chmod
来运行./semester
命令,而不是输入sh semester
。你的shell怎么知道应该使用sh
解释文件?有关更多信息,请参阅shebang。
When a text file with a shebang is used as if it is an executable in a Unix-like operating system, the program loader mechanism parses the rest of the file’s initial line as an interpreter directive. The loader executes the specified interpreter program, passing to it as an argument using the path that was initially used when attempting to run the script, so that the program may use the file as input data. For example, if a script is named with the path path/to/script, and it starts with the following line,
#!/bin/sh
, then the program loader is instructed to run the program /bin/sh, passing path/to/script as the first argument. In Linux, this behavior is the result of both kernel and user-space code.
hmt@missing:/tmp/missing$ chmod u+x semester
hmt@missing:/tmp/missing$ ll
总用量 12
drwxrwxr-x 2 hmt hmt 4096 5月 25 21:43 ./
drwxrwxrwt 25 root root 4096 5月 25 21:43 ../
-rwxrw-r-- 1 hmt hmt 61 5月 25 21:43 semester*
给hmt
用户添加x
执行权限
10.使用|
和>
将semester
输出的“last modified”日期写入home
目录中的last-modified.txt
文件。
hmt@missing:/tmp/missing$ sh semester | sed -n "4,4p" > last-modified.txt
11.写一个命令,从/sys
读取你的笔记本电脑电池的电力水平或你的桌面电脑的CPU温度。注意:如果你是macOS用户,你的操作系统没有sysfs
,所以你可以跳过这个练习。
hmt@missing:/$ cat /sys/class/power_supply/BAT0/capacity
100
hmt@missing:/$ cat /sys/class/thermal/thermal_zone1/temp
42000
hmt@missing:/$ cat /sys/class/thermal/thermal_zone2/temp
46000