聽說你入行好幾年還只會cd和ls,麻省理工開了這門課……

語言: CN / TW / HK

大家好,日拱一卒,我是梁唐。本文始發於公眾號Coder梁

不知道大家有沒有這樣一種體驗,在實際寫程式碼或者是工作、做專案的過程當中經常被一些簡單的問題難住。比如vim的一些命令不熟悉,或者是git的一些操作不知道怎麼弄,命令列除了ls cd之外一無所知。總覺得書到用時方恨少。

別說是還沒畢業的學生了,即使是一些畢業多年的程式設計師老鳥也難免會查查谷歌或者Stack Overflow。我每次遇到這樣問題的時候總會忍不住想, 要是上學的時候學校裡能專門開一門課程講一講這些基本工具的使用,給學生做一個深度的科普,該有多好。

也許是聽到了眾多程式設計師的心聲,2020年的時候,MIT開設了一門公開課。它的標題很有意思,叫做《missing smester》,消失的學期。課程當中收錄的正是這些大部分學校課程當中不會專門涉及,但是又至關重要的基礎知識。

課程量不算大,算上最後的答疑部分,一共也只有十一節課。但這十一節課當中包含了命令列、git、vim等許多非常重要的知識和技能,非常非常值得一看。

雖然課程裡講的內容非常基礎,但溫故知新,我也收穫了非常多。因此強烈推薦給大家。

B站課程連結

課程筆記

動機

作為電腦科學家,我們知道計算機非常擅長處理高重複性的任務。

然而我們嚐嚐忽略,我們使用計算機的過程其實和計算機處理程式時類似,也一樣充滿了重複。我們在處理計算機相關的問題上擁有大量的工具可以使用,只需要動動手指輸入命令或程式,就可以完成一些高度複雜的任務。

然而,我們當中的很多人,只使用了這些工具的很小一部分。有時候僅僅是死記硬背了一些命令,或者是在遇到困難的時候,盲目地從網上覆制貼上命令。

這門課檢視解決這個問題,我們希望教會你如何最大限度地使用這些工具,給你展示一些新的工具豐富你的技能樹,給你更多的鼓舞和興趣,讓你勇敢地探索。這就是我們對電腦科學領域中消失的學期的定義。

課程結構

這門課包含了11個長度約1小時的課程,每一節課都有一個特定的主題。

每節課之間都是高度獨立的,但在課程進行的過程當中,我們還是會假設你已經學會了之前的內容。我們會把課程的筆記公開在網上,但也有很多課上的內容是筆記裡沒有的。上課的影片也同樣會放在網上。

我們嘗試著在11小時的課程當中儘可能多地包含基礎知識,所以課程的內容會比較密集。為了保證你們能順利地跟上節奏,每節課後都會有針對要點的一系列練習。

由於時間的限制,所以沒辦法對所有的工具都進行深入的探討。可能的話,我們會試著提供繼續鑽研和學習的資源。

Topic 1: The Shell

什麼是 shell?

現代的計算機擁有大量的方式和使用者進行互動,美觀的使用者介面、聲音甚至是AR或者是VR都已經逐漸普及。

對於80%的使用者來說,這已經足夠了,但這也意味著很多基本功能的限制。因為你沒辦法進行圖形介面中沒有的操作,也沒辦法聲控一個沒有開發的功能。為了充分應用計算機的功能,解除圖形介面的限制,我們需要回到上古時期,使用文字介面來控制計算機,這個就是shell。

幾乎所有的平臺都有shell,只不過它們的形式可能不同。儘管細節上有所區別,但核心都是一樣的:允許你執行程式,輸入指令,顯示結果。

在這節課當中,我們將聚焦在Bourne Again Shell上,簡稱bash。這也是使用最廣泛的shell,它的語法和其他的shell也非常接近。為了開啟shell介面,你需要一個terminal(終端)。一般來說,計算機當中都會自帶,你也可以自己安裝一個。

使用shell

當你開啟terminal,你會看到一個游標,大概長這樣:

這個是shell的主要文字介面,它告訴你,你當前的工作路徑是機器上missing,並且你當前所在的地方是~,這是home的簡稱。

$符號說明你不是一個超級使用者(root user),我們將會詳細解釋root user。你可以在游標處輸入指令,它會被shell解讀並執行。最基礎的命令是執行一個程式:

現在我們運行了date程式,它會列印當前的日期和時間。之後shell會繼續讓我們輸入指令,我們可以輸入一個帶引數的指令:

在這個例子當中,我們告訴shell執行一個叫做echo的程式,引數是hello

echo程式會把引數進行輸出,shell會按照空格對命令進行拆分。以第一個單詞作為程式名進行執行,將剩餘的單詞作為引數。如果你想要傳遞一個帶有空格或者其他特殊字元的引數,需要使用引號(如"My Photos")或者是取義符(My\ Photos)。

但shell是怎麼知道去哪裡尋找dateecho程式的呢?

其實shell只是一個程式設計環境,就像是Python和Ruby一樣,所以它也有變數、條件、迴圈和函式。當你在shell中執行命令的時候,你其實是編寫了一個簡易的程式碼交給了shell來解釋執行。

當shell被要求執行一個不是shell中的關鍵字的命令時,它會去環境變數$PATH中進行查詢。$PATH中包含了一系列資料夾路徑以:分隔,shell會在這些路徑當中找到名稱匹配的程式進行執行。

當我們執行echo命令時,shell發現它不在shell的關鍵字中之後,會先在$PATH路徑當中進行查詢。

當找到之後,就會進行執行(假設有許可權執行,許可權這部分之後講解)。我們可以使用命令which找到我們執行的程式所在的路徑。我們也可以自己給定我們要執行的程式的路徑來繞過path機制。

shell中的指引

shell中的path是一系列資料夾組成的list,在Linux和macOS當中以/分隔,在Windows當中以\分隔。

在Linux和macOS當中,/路徑表示系統的根目錄,是所有檔案和路徑的根節點。而Windows當中磁碟的根目錄會有多個分割槽,比如C:\。我們會假設你在這門課程中使用的是Linux檔案系統。

/開頭的路徑被稱為絕對路徑,其他的路徑都是相對路徑。相對路徑是相對於當前路徑而言的路徑,我們可以通過命令pwd來檢視當前路徑,通過cd命令來修改當前路徑。.代表當前路徑,..代表當前路徑的父路徑。

注意,圖中的shell提示了我們當前所在的路徑,這是可以配置的。你可以修改你的終端的配置,顯示所有你需要的資訊,這也會在之後的課程當中提及。

總的來說,當我們執行一個程式時,除非指定,它會在當前目錄執行。

檢視當前路徑中的內容,可以使用ls命令:

除非我們在第一個引數中輸入一個路徑,否則它會列出當前路徑下的內容。

大多數命令都會有flags和options,通過-接收引數來指定行為。通常執行程式時加上-h--help flag可以得到一些幫助資訊告訴我們每個flag和options如何使用。

比如ls --help告訴我們:

加上引數-l之後會得到關於檔案的更多的資訊。我們看一下輸出結果:

開頭的d表示missing是一個資料夾,然後緊跟著一系列字元(rwx),這些表明了這個檔案/資料夾的許可權。許可權一共有9個字母,分成三組。

第一組rwx表示表示檔案owner的許可權,r表示可讀,w表示可寫,x表示可執行。

第二組r-x表示所屬群組(users)的許可權,每個字母表示的含義和owner相同,-表示沒有這一項許可權。比如r-x表示可讀可執行,但不可寫。

第三組r-x表示其它使用者的許可權。所以只有owner擁有修改missing資料夾的許可權,包括新增、刪除資料夾內的檔案的許可權。

要進入一個路徑,使用者必須擁有這個資料夾以及它所有父路徑的search(執行)許可權,要列出資料夾中的內容,使用者需要有資料夾的讀許可權。

需要注意/bin路徑下幾乎所有檔案對其它使用者都只有執行許可權,這樣保證了所有的使用者都可以執行這些程式。

其他一些很有用的命令還有mv(重新命名、移動檔案),cp(拷貝檔案),mkdir(建立資料夾)。

如果你想要知道一個程式引數、輸入、輸出的更多資訊,你可以使用man程式。它接收另外一個程式名作為引數,然後展示它的使用選單,輸入q進行退出。

Connecting programs

在shell當中,程式擁有兩個流,即輸入流和輸出流。當程式試著讀入資料時,它是從輸入流獲取的。當它試著輸出時,也是向輸出流進行傳輸。

一般來說,程式的輸入和輸出裝置都是你的終端,也就是以我們的鍵盤作為輸入,以螢幕作為輸出。然而,我們可以修改這些流。

最簡單的方式就是重定向流,比如< file> file,表示我們以一個檔案作為輸入,或者是以一個檔案作為輸出:

像是上面例子所演示的,cat程式可以輸出檔案中的內容。當我們給定一個檔案作為引數,它會輸出檔案中的內容到它的輸出流上。當cat沒有任何引數的時候,它會將輸入流中的內容輸出到輸出流中(上面第三個樣例)。

你也可以使用>>代替>,它們的區別是>>不會替換檔案中的內容,而是新增在檔案末尾。這些特性結合管道一起使用的時候會非常有用,|命令可以讓我們在程式之間構建管道。讓一個程式的輸出作為另外一個的輸入:

在本節課中,不會太過深入管道的細節,以及它的優勢,這部分放在之後的課程中。

多功能且強大的工具

在大多數類Unix系統當中,有一種使用者是特殊的,它就是root。

root使用者超越了所有許可權的限制,它可以建立、讀入、更新、刪除系統中的任何檔案。然而,你不能一直使用root,因為這會非常危險,可能破壞你的系統或者是導致不可逆傷害。

你可以使用sudo命令代替,就像是它的名稱暗示的一樣,它允許你像root一樣執行某些操作。有時候你會獲得permission denied錯誤,這表示你沒有許可權。你可以使用sudo來強行執行,不過在執行之前,一定要確保你的命令是正確的。

有一件你必須要是root才可以做的事情:修改系統檔案。

系統檔案通常掛載在/sys路徑下,當中將一些核心引數以檔案的形式儲存。所以你可以很輕易地修改一些核心引數。需要注意的是,/sys檔案在windows和macOS中沒有。

比如,你可以通過修改一個名叫brightness的檔案來調整你筆記本螢幕的亮度:

通過往檔案中寫入一個特定的值,你可以修改螢幕的亮度。

你的整個執行過程可能是這樣的(你可能需要先通過find命令找到對應的檔案):

bash $ 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中一個我們需要了解非常重要的資訊,像是|這樣的管道命令,或者是>, <分隔的命令,並不是一個單獨的程式。echo並不知道|命令的存在,它僅僅是讀入和輸出。

在上面的例子中,shell在echo 3時以root執行,而開啟brightness檔案時沒有,仍然是普通使用者。所以被拒絕了,如果我們想要以root執行寫入,我們可以這樣改寫命令:

bash $ echo 3 | sudo tee brightness

tee程式可以同時寫入/sys檔案,並且以root身份執行,所以不會受到許可權限制。

你可以控制/sys下的一些檔案來娛樂或實現一些功能。比如說開啟一些LED指示燈,下列程式碼會開啟scrolllock指示燈。

bash $ echo 1 | sudo tee /sys/class/leds/input6::scrolllock/brightness

Next steps

現在你已經瞭解了shell的一些基本應用,可以來完成一些基礎功能了。

你應該可以跳轉到任何你感興趣的路徑下,並且能夠使用基礎命令的絕大多數功能了。在下節課當中,我們將會接觸到更多有趣的命令,並且使用shell來實現更加複雜的一些任務。

Exercises

這門課每節課後都會附帶一些練習,有一些是給定了指定的任務去完成,也有一些是開放式的任務,比如說嘗試使用X或Y程式。我們強烈推薦你能親自嘗試。

  1. 這門課我們需要使用Unix shell,比如Bash或者Zsh。如果你使用Linux或者是macOS,那你並不需要為此煩惱。如果你使用的是Windows,你需要確保你執行的不是cmd.exe或者PowerShell。你可以使用Windows Subsystem for Linux或者使用Linux虛擬機器來使用Unix風格的命令列。為了確保你使用了正確的shell,你可以嘗試執行命令echo $SHELL,如果顯示的結果是/bin/bash或者/usr/bin/zsh,那麼久說明你處在了正確的環境
  2. /tmp路徑下建立missing資料夾
  3. 使用man程式來調研touch程式
  4. 使用touchmissing下建立semester檔案
  5. 在檔案當中寫入以下兩行,一次寫入一行:

```bash

!/bin/sh

curl --head --silent http://missing.csail.mit.edu ```

第一行是Bash中的註釋,Bash中以#開啟註釋。!即使在雙引號當中也有特殊含義。在Bash當中,單引號和雙引號是有區別的,你可以調研一下它們的區別

  1. 嘗試執行這個檔案,你可以使用./semester來執行。使用ls命令來探究不能執行的原因
  2. 使用sh命令,將semester作為引數傳入執行程式,如sh semester,為什麼這樣可以執行,為什麼./semester不行?
  3. 調研chmod程式,使用man chmod
  4. 使用chmod來讓./semester可行。你的shell怎麼會知道這個檔案應該用sh執行呢?瞭解一下shebang獲得更多資訊
  5. 使用|>semester輸出結果中 "last modified" 日期寫入到你home下的last-modified.txt
  6. 編寫命令讀取/sys中你筆記本電源的電量或者筆記本CPU的溫度,如果你是macOS使用者,你的作業系統可能沒有/sys檔案,你可以跳過本題

答案

前六題的命令為:

bash cd /tmp mkdir missing touch semester echo '#!/bin/sh' > semester echo 'curl --head --silent http://missing.csail.mit.edu' >> semester ./semester

img

直接執行會報錯,因為沒有執行許可權。

img

使用命令給semester新增執行許可權:

bash chmod +x semester

shell能知道這個檔案使用什麼程式執行是因為我們在第一行加上了特殊的註釋:#!/bin/sh,這是指定了該檔案執行的程式。

最後,將篩選資料寫入檔案:

bash ./semester | grep 'last-modified' > ~/last-modified.txt