Bash是目前大多數系統上的默認shell,包括Linux、macOS以及Windows 10上的WSL。

註:自Catalina(2019年秋季)以來,macOS使用Zsh

有一些歷史原因使得Bash成為世界上最受歡迎的shell。在1989年,當Bash首次發布時,技術世界與現在相去甚遠。當時,UNIX世界中的大多數軟件都是封閉源碼的。Unix本身是專有的,也是封閉源碼的。

要使用Unix系統,您必須使用一個shell。

當時最受歡迎的shell是封閉源碼的,您需要支付費用才能使用它。它被稱為“Bourne shell”,在/bin/sh命令下可用。它之所以被稱為“Bourne”是因為它的創作者是Steve Bourne。

在那些年,Richard Stallman與GNU項目(後來又是Linux)即將引起革命,開始了開源革命。 GNU項目需要一個shell,於是Bash應運而生。Bash受到Bourne Shell的極大啟發,Bash代表“Bourne再次shell”,它是GNU項目的一個重要組成部分,也是該項目最成功的軟件之一,我們仍然在今天使用。

Bash可以執行所有為sh編寫的腳本,這對於其采用是一個必要的功能,它還引入了更多功能,從最早的版本開始,為其用戶提供更好的體驗。從那時以來,Bash獲得了很多改進。本教程介紹了您可以使用Bash執行的最常見和有用的操作。

Bash的第一步

由於Bash是許多系統的默認shell,您只需要開始bash shell就只需以下操作:

  • 登錄到系統(如果是服務器)。
  • 打開終端(如果是您的計算機)。

開始shell後,您應該看到一個提示符(通常以$結尾)。

如何確定shell正在運行bash?請嘗試輸入help並按Enter。

看到了嗎?我們剛才告訴Bash執行help命令。該命令顯示您正在運行的Bash版本以及您可以使用的命令列表。

警告:看到我那裡有的版本了嗎?這是macOS隨附的默認Bash版本,由於許可問題,它不包含更高版本。這個Bash版本來自於2014年。輸入brew install bash使用Homebrew安裝最新的Bash 5.x。

除非您正在創建shell腳本或進行高級操作,否則您通常不會使用bash說明中列出的任何命令。

99%的日常shell使用是在文件夾之間導航和執行像lscd和其他常見UNIX實用程序的程序。

瀏覽文件系統

要瀏覽文件系統,您將使用ls命令。它在/bin/ls中可用,並且由於Bash將/bin文件夾列在其路徑列表中,因此您只需輸入ls即可使用它。

ls會列出當前文件夾中的文件。您通常從您的主文件夾開始,它取決於系統,但在macOS下位於/Users下。我的主文件夾位於/Users/flavio。這與Bash無關,而是有關UNIX文件系統的事情,但參數重疊,如果您從未使用過shell,了解這些是很有益的。

要導航到其他文件夾,請使用cd命令,後跟要移動到的文件夾的名稱:

cd Documents

cd ..會返回到上級文件夾。

根據您的Bash配置,您將在提示符($符號)之前看到您當前的文件夾。或者,您可能不會看到它,但您始終可以通過輸入“pwd”並按Enter來知道您的位置。

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允許您更改文件的所有者。

cattailgrep 是處理文件的兩個非常有用的命令。

一些常見的文本編輯器是piconanovimemacs

在macOS上,whereis命令將顯示系統上命令的位置。

還有許多其他命令,但這些是您可能經常遇到的幾個命令。

執行命令

lscd是命令,正如我之前提到的,它們可以在/bin文件夾找到。您可以執行任何文件,只要它是可執行文件,輸入完整路徑,例如/bin/pwd。命令不需要在/bin文件夾中,您可以使用 ./路徑指示符執行當前文件夾中的可執行文件。

例如,如果您的/Users/flavio/scripts文件夾中有一個runme文件,您可以運行

cd /Users/flavio/scripts

然后運行 ./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>來終止作業或進程。

命令歷史

上箭頭鍵將顯示您輸入的命令的歷史記錄。這又是一個shell的特點。按 下箭頭鍵可在時間軸上前進和後退以查看以前輸入的命令,按 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是否作為“登錄shell”初始化是一個重要的區分。登錄shell表示系統未運行GUI(圖形用戶界面),您通過shell登錄到系統。這是服務器的情況,例如。

在這種情況下,Bash加載此配置文件:

/etc/profile

然後它在用戶主目錄下查找這些文件,並按照次序執行第一個找到的文件:

~/.bash_profile
~/.bash_login
~/.profile

其中~意味着您的主目錄(Bash會自動將其轉換)。

這意味著如果有.bash_profile~/.bash_login~/.profile永遠不會運行,除非在.bash_profile中顯式運行它們。

如果不是登錄shell應用程序(例如macOS),而是像我這樣作為一個普通應用程序運行的Bash,則配置文件會更改。Bash首先加載/etc/bash.bashrc,然後是~/.bashrc

環境變量

有時候您可能有使用環境變量的程序。這些是您可以在程序之外設置的值,並改變程序本身的執行。例如,API密鑰或文件名。

您可以使用以下語法來設置環境變量:

VARIABLE_NAME=variable_value

值可以包含空格,使用引號:

VARIABLE_NAME="variable value"

bash腳本可以通過在變量前面加上美元符號 $ 使用此值。

其他編程語言命令也可以使用環境變量,例如這裡是如何使用Node.js讀取環境變量。

系統會為您設置一些環境變量,例如:

  • $HOME:您的主目錄
  • $LOGNAME:您的用戶名
  • $SHELL:您的默認shell的路徑
  • $PATH:shell在查找命令時的路徑

您可以通過在這些變量前面加上echo來檢查其值:

echo $LOGNAME # flavio
echo $HOME # /Users/flavio

一個特殊的環境變量:$PATH

我之前提到了$PATH變量。這是一個列出shell在輸入命令時搜索的文件夾的列表。文件夾由冒號:分隔,按順序排列- Bash首先查找第一個命令,如果找到了該命令,就執行它。否則,如果命令不在該文件夾中,則查找下一個文件夾,依此類推。

我的$PATH當前是:

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>

如果命令中有空格,請使用引號:

alias <alias>="<command>"

我通常在系統中添加的一個別名是ll

alias ll="ls --al"

通常在~/.bashrc文件中定義別名。

但是,如果您的命令中有變量,請小心引號:使用雙引號解析變量時已定義的值,使用單引號將在調用時解析變量。這兩個是不同的:

alias lsthis="ls $PWD"
alias lscurrent='ls $PWD'

$PWD指的是shell所在的當前文件夾。如果現在導航到新文件夾,lscurrent將列出新文件夾中的文件,lsthis仍將列出您在定義別名時的文件夾中的文件。

高級命令行功能

通配符

ls和許多其他命令可以充分利用通配符。您可以列出所有以"image"開頭的文件:

ls image\*

或列出以“image”結尾的所有文件:

ls \*image

或列出所有名稱中包含“image”的文件:

ls \*image\*

重定向輸出和錯誤

默認情況下,shell中啟動的命令將輸出和錯誤信息打印到shell中。這可能不是你想要的。您可以決定將輸出寫入文件。

實際上,寫入到/不同的文件/,因為在Unix中,即使屏幕也被視為一個文件。具體來說,

  • 0 代表標準輸入
  • 1 代表標準輸出
  • 2 代表標準錯誤

您可以在命令後附加1>,然後是文件名,將標準輸出重定向到文件。

使用相同的技巧,您可以使用2>將標準錯誤寫入文件。

快捷方式>表示1>,因為這更常用。

例如:

ls 1> list.txt 2> error.txt
ls > list.txt 2> error.txt

快捷方式&>將標準輸出和標準錯誤都重定向到文件。

ls &> output.txt

另一種常見的情況是使用2>&1將標準錯誤重定向到標準輸出。

在後台運行命令

您可以告訴Bash在後台運行一個程序,而無需它佔用shell的控制權,只需在它後面加上&

例如:

top &

top是一個按消耗最多資源的順序列出正在運行的進程的命令。

本來應該獲得shell控制權的應用程序現在啟動,但似乎什麼都沒發生。您可以輸入fg(即foreground)將它帶回前台,但我們現在進入了進程和作業的領域,這本身是一個很大的主題,但快速總結一下:

當命令運行時,您可以使用ctrl-Z將其暫停並將其放入後台。shell再次出現在前景中,然後可以用bg恢復先前暫停的作業的執行。

當您準備返回它時,運行fg將在前台顯示該程序。

您可以使用ps查看正在運行的所有進程,列表顯示所有進程的pid號。使用已暫停的進程pid號,您可以將一個特定的命令帶回前台,例如fg 72292bg也是一樣的工作方式。

队列命令

您可以通過分號將兩個命令隔開,使Bash在第一個命令結束後立即運行第二個命令:

cd /bin; ls

您可以重複此操作,將多個命令排隊在同一行中。

輸出重定向

程序可以使用<運算符從任何文件接收輸入,使用>運算符將輸出保存到文件中:

echo hello > result.txt
wc < result.txt

wc是一個計算接收到的單詞的命令。

管道

使用管道,可以將任何命令的輸出作為第二個命令的輸入。使用|運算符將兩者結合到一起。在這個例子中,wcecho hello的輸出中獲取它的輸入:

echo hello | wc

組合命令

使用&&使用“and”組合兩個命令。如果第一個命令正常運行,那麼運行第二個命令,以此類推。

使用||使用“or”組合兩個命令。如果第一個命令正常運行,則不運行第二個命令。

!否定下一個邏輯操作:

$ 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

編程shell

像Bash這樣的shell的最佳功能之一是它可以創建程序,通過基本上自動化命令的執行。

我將很快寫一篇關於Bash腳本的單獨指南,這將與本入門Bash指南分開,因為該主題比我想在本指南中添加的更詳細。

簡單介紹一下:腳本是文件以文本格式開始,此行指示它是shell腳本(以及需要哪個shell),然後是一行一行的命令列表,例如:

#!/bin/bash
ls

您可以將其保存為文件myscript,並使用chmod +x myscript使其可執行,然後使用./myscript運行它(./表示“當前文件夾”)。

shell腳本超出了本篇文章的範圍,但我希望您瞭解這一點。腳本可以具有控制結構和許多其他很酷的功能。

這種編程策略對於其他shell(例如Zsh)也同樣有效。