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使用是在文件夾之間導航和執行像ls
,cd
和其他常見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
允許您更改文件的所有者。
cat
,tail
和grep
是處理文件的兩個非常有用的命令。
一些常見的文本編輯器是pico
,nano
,vim
和emacs
。
在macOS上,whereis
命令將顯示系統上命令的位置。
還有許多其他命令,但這些是您可能經常遇到的幾個命令。
執行命令
ls
和cd
是命令,正如我之前提到的,它們可以在/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 72292
。bg
也是一樣的工作方式。
队列命令
您可以通過分號將兩個命令隔開,使Bash在第一個命令結束後立即運行第二個命令:
cd /bin; ls
您可以重複此操作,將多個命令排隊在同一行中。
輸出重定向
程序可以使用<
運算符從任何文件接收輸入,使用>
運算符將輸出保存到文件中:
echo hello > result.txt
wc < result.txt
wc
是一個計算接收到的單詞的命令。
管道
使用管道,可以將任何命令的輸出作為第二個命令的輸入。使用|
運算符將兩者結合到一起。在這個例子中,wc
從echo 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)也同樣有效。