之前用 AWS 做計(jì)算的時(shí)候臨陣磨槍地接觸到了一些 Linux 的命令,但這種現(xiàn)學(xué)現(xiàn)賣的方式學(xué)到的終究都是只言片語,一直想花時(shí)間來了解一下為什么 Linux 在代碼世界中具有這樣不凡的地位。這段時(shí)間剛好有些空閑,決定系統(tǒng)的學(xué)習(xí)一下。找了半天資料之后,在 edX 上找到了 Linux Fundation 官方制作的 Introduction to Linux 這門課,由傳奇的 Linus 本人親自作序,內(nèi)容非常的全面,是一個(gè)系統(tǒng)的熟悉 Linux 的好方式。
作為人類歷史上最著名和最大規(guī)模的開源項(xiàng)目(沒有之一),Linux 幾乎遍布在世界上所有 IT 技術(shù)可以觸及到的領(lǐng)域,小到手機(jī)、開發(fā)板,大到航天飛機(jī)、大型機(jī)、數(shù)據(jù)中心,基于 Linux 內(nèi)核的不同版本的 Linux 系統(tǒng)都在背后默默支持著環(huán)境的穩(wěn)定運(yùn)行,單憑這一點(diǎn),Linux 就值得每一個(gè)技術(shù)工作者去學(xué)習(xí)和了解。
很多知識作為靜態(tài)的信息,在有一定程度的了解之前很容易先入為主的給予一些偏見。但當(dāng)你投入一定的時(shí)間對其進(jìn)行深入理解之后,就會(huì)發(fā)現(xiàn)自己之前的觀念是錯(cuò)誤甚至是愚蠢的。之前一直以為 Linux 的命令行 command line 是一個(gè)玄學(xué),但這兩天開始了這個(gè)系列的課程之后,才頓悟圖形界面 Graphic User Interface, GUI 只是人機(jī)交互的一種(我承認(rèn)我智商低,反應(yīng)慢),而不一定所有場景(例如開發(fā)板)都可以(需要)實(shí)現(xiàn) GUI 的支持,在這些場合下,Command Line Interface, CLI 就大有裨益了。
Graphical user interfaces make easy tasks easier, while command line interfaces make difficult tasks possible.
Graphic User Interface, GUI 交互
在圖形界面交互的設(shè)計(jì)方面,由于最終都會(huì)依從人類本能的使用習(xí)慣,各個(gè)系統(tǒng)之間的差異并不大,因此對于熟悉 Windows 系統(tǒng)的人來說帶有 GUI 的 Linux 系統(tǒng)非常容易上手。在這里僅記錄一些快捷鍵和命令,以備后續(xù)查詢使用:
- lock screen:
SUPERUSER + L - view location:
CRTL + L - find something:
CRTL + F - view files with icons or list formats:
CRTL + 1orCRTL + 2 - show hidden:
CRTL + H
Command Line Interface, CLI 交互
對于 CLI 交互來說,與其死記硬背那些命令,不如理解這些命令的由來,以及其對應(yīng)的英文單詞原意,這樣無論對于記憶還是理解這個(gè)命令都非常有幫助,在此基礎(chǔ)上慢慢熟悉起來就好。例如:
在 Linux 下最常用的終端 bash 指代的是 Bourne Again Shell,是對早期的 Steve Bourne 版本的 sh shell 的一個(gè)升級和致敬
對于 Debian 系列的系統(tǒng)來說,底層的軟件安裝的管理都?xì)w屬于
dpkg,其對應(yīng)的英文單詞為debian pakage,而對應(yīng)的更高級別的軟件管理系統(tǒng)則是apt,也即 advanced package tools,對應(yīng)的安裝和搜索文件的命令為apt-get install和apt-cache search
理解命令行命令的另外一個(gè)好處是這些常用的命令在很多編程語言的函數(shù)設(shè)計(jì)中都作為函數(shù)的名稱或名稱的一部分,因此也可以促進(jìn)其他編程語言的學(xué)習(xí)。
Most input lines entered at the shell prompt have three basic elements:
- Command
- Options
- Arguments
The command is the name of the program you are executing. It may be followed by one or more options (or switches) that modify what the command may do. Options usually start with one or two dashes, for example, -p or --print, in order to differentiate them from arguments, which represent what the command operates on.
在 Linux 中所有通過 GUI 能夠完成的任務(wù)都可以通過 CLI 來完成——前提是輸入合適的命令。鑒于 Linux 命令眾多,這里僅記錄一些比較常用但之前不太熟悉的命令和概念:
sudo commands:以 superuser 的身份來執(zhí)行某個(gè)命令 (super user do...)遠(yuǎn)程訪問:
sshsecure shell 是最常用的安全加密訪問協(xié)議,其背后的加密算法基于 Secure Hashing Algorithms 512 bits, SHA-512,這也是 SSL 等其他加密協(xié)議采用的加密算法定位應(yīng)用程序的位置:
which / whereis app_name定位系統(tǒng)中的文件位置:
locate file_name,需要注意的是locate這一命令的執(zhí)行需要基于一個(gè)預(yù)先建立好的包含系統(tǒng)中的全部文件的數(shù)據(jù)庫,Linux 系統(tǒng)會(huì)默認(rèn)的每 24 小時(shí)執(zhí)行一次備份,如果想要手動(dòng)執(zhí)行可以使用sudo updatedb命令。另外如果需要更加精確的指定文件中包含的字符,可以通過添加 pipe 來完成:locate file_name | grep some_string,這里some_string還可以結(jié)合通配符 wildcards 來進(jìn)一步提高檢索能力快速文件的定位:當(dāng)想要執(zhí)行小范圍的文件查找時(shí),應(yīng)該采用
find命令,例如在 /usr 目錄下查找文件名為 gcc 的文件:find /usr -type f -name gcc查看當(dāng)前工作目錄:
pwd(present working directory)通配符 wildcards:這里的通配符與 regular expression 中的定義相同,幾個(gè)常用的通配符如下:
?匹配任意單個(gè)字符,*匹配任意多個(gè)字符,[set]匹配 set 中的任意一個(gè)或多個(gè)字符,[!set]匹配不包含在 set 中的任意一個(gè)或多個(gè)字符多通道 pipes:在 Linux 和 Unix 系統(tǒng)的命令設(shè)計(jì)思想中,作者希望能夠?qū)⒍鄠€(gè)簡短的命令組合在一起來執(zhí)行復(fù)雜的任務(wù),因此設(shè)計(jì)了多通道這一操作,其實(shí)現(xiàn)方式為:
command1 | command2 | command3,對于多核的 CPU 和具有并行計(jì)算能力的硬件來說,不同命令之間不一定需要順序執(zhí)行軟硬鏈接:在 Linux 系統(tǒng)內(nèi)部文件的身份是通過 inode (index node) 號來識別的,如果兩個(gè)文件共享同一個(gè) inode 號,則將二者之間的關(guān)系稱作硬鏈接 hard link。對于已有的一個(gè)文件創(chuàng)建硬鏈接相當(dāng)于將這個(gè)文件復(fù)制到了目標(biāo)目錄下,而使得整個(gè)文件可以被目標(biāo)目錄共享使用,但同時(shí)卻只占用一個(gè)文件的存儲(chǔ)空間。硬鏈接的創(chuàng)建方式為
ln file_name link_name;與硬鏈接相對應(yīng)的,我們可以通過在ln命令后添加-s選項(xiàng)來創(chuàng)建軟鏈接 soft link (symbolic link),軟鏈接的實(shí)質(zhì)可以理解為 windows 下的超鏈接,通過軟鏈接創(chuàng)建的新文件中的數(shù)據(jù)內(nèi)容為原有文件的位置信息創(chuàng)建目錄:
mkdir /directory刪除操作:
rm -i dirctory(i: interectively),謹(jǐn)慎使用rm -rf /directory(rf: remove forcefully),否則可能闖下大禍移動(dòng)和重命名文件及目錄:
mv /directory1 /directory2,這里需要特別注意mv既可以完成移動(dòng)也可以完成重命名操作,當(dāng)前后兩個(gè)目錄相同而文件名不同時(shí)即完成重命名輸入和輸出:在 Linux 中默認(rèn)的輸入
stdin的來源是鍵盤,而默認(rèn)的輸出stdout是終端,而這些輸入和輸出的位置可以通過<和>來更改定時(shí)關(guān)機(jī):
sudo shutdown -h 10:00 "routine maintenance."快捷別稱:在 Linux 日常使用中,如果某些命令使用的頻率較高,則可以通過自定義別稱來實(shí)現(xiàn)快速執(zhí)行,例如假設(shè)需要經(jīng)常性的通過
cd訪問一個(gè)公共的項(xiàng)目目錄cd /home/staff/RandD/projects/projectX/src則可以通過alias projectX='cd /home/staff/RandD/projects/projectX/src'來為上述路徑切換命令創(chuàng)立一個(gè)快捷訪問方式,后續(xù)只要在 Terminal 中輸入projectX即可

環(huán)境變量:環(huán)境變量本身就是一系列特定的字符串,其可以被一個(gè)或多個(gè)程序訪問以實(shí)現(xiàn)特定的目的,在 Linux 中可以通過
set,env或export來查看已有的環(huán)境變量設(shè)置。最常用的一個(gè)環(huán)境變量是PATH,其內(nèi)容為一系列順序排列的路徑,程序在運(yùn)行時(shí)會(huì)依次的在這些路徑中尋找所需的文件,可以通過echo $VARIABLE來查看環(huán)境變量中的內(nèi)容文檔訪問:Linux 配置了非常強(qiáng)大的文檔系統(tǒng),可以通過
man -f command_name來訪問程序的文檔系統(tǒng),其替代方法還包括info command_name或command_name --help文件屬性:在 Linux 中文件的擴(kuò)展名不像在 Windows 下那樣對于文件的類型具有確定性,也即
file_name.txt不一定是文本文件,對此可以通過file file_name來確認(rèn)文件的真實(shí)屬性文件歸檔:Linux 中常用的文檔歸檔命令
tar是 tape archive 的縮寫,這個(gè)應(yīng)用可以與壓縮工具聯(lián)合使用來將多個(gè)文件及目錄打包成一個(gè)壓縮文件或者解壓一個(gè)壓縮文件,例如tar xvf file_name.tar.gz文件備份:除可以使用
cp命令外,還可以使用rsync命令,后者會(huì)首先檢查待備份的文件是否發(fā)生改動(dòng),并只備份改動(dòng)的部分,因此更加高效,rsync另外一個(gè)優(yōu)點(diǎn)是可以實(shí)現(xiàn)遠(yuǎn)程/多機(jī)備份文件顯示:
cat一般可以用于顯示文本文件內(nèi)的內(nèi)容,但當(dāng)提供多個(gè)文件名時(shí)可以將兩個(gè)文件內(nèi)的容用連接 catenate 在一起顯示,還可以聯(lián)合>和>>來復(fù)制和添加文件中的內(nèi)容到新的文件中。當(dāng)被讀取的文件過長時(shí),可以采用head或tail來顯示前后10行的內(nèi)容,或者采用less filename和cat filename | less來分頁顯示。除cat外echo commands [strings]也常被用作打印后續(xù)命令的輸出結(jié)果,和環(huán)境變量查詢顯示,如echo $PATH,echo $HOME文件生成:
cat和echo也常用于在命令行中直接生成文本文件,如cat file1 file2 > newfile.txt或cat > newfile.txt創(chuàng)建一個(gè)新文件,后續(xù)輸入的每一行會(huì)被自動(dòng)添加到文件中,直到ctrl + D終止,之后如果還想繼續(xù)添加可以輸入cat >> newfile.txt完成。對應(yīng)的執(zhí)行相同操作的echo命令如下:echo line1 > some_file,echo line2 >> some_file,echo line3 >> some_file文件更新:
touch file_name可以創(chuàng)建新文件或者更改已有文件的時(shí)間戳文件傳輸:在 Linux 下如果需要執(zhí)行較大的文件下載或者多個(gè)相互鏈接的文件的連續(xù)下載,推薦使用這個(gè)命令
wget <url>,對于兩臺主機(jī)之間的加密文件傳輸可以使用scp local_file user@remote_system: /directory來完成壓縮文件:針對壓縮文件,上述文件操作命令還有一個(gè)對應(yīng)的壓縮文件版本,如
zcat,zless,zgrep,zdiff,具體使用語法與相應(yīng)的命令相同:zcat compressed-file.txt.gz
Shell Scripts
除了逐行的手動(dòng)在 shell 中輸入命令之后,CLI 交互的更強(qiáng)大之處是其可以通過直接運(yùn)行 Shell Scripts 來執(zhí)行一系列的任務(wù),也即通過 CLI 運(yùn)行一段寫好的程序。

在 Linux 中 Scripts 文件的開頭以
#!/bin/bash作為第一行,其包含的是即將用于運(yùn)行文件中的代碼的解釋器 interpreter 的位置,例如如果即將運(yùn)行的是Python 代碼,則可以將其更改為諸如#!/usr/bin/env python樣式的字符串如果腳本是通過
cat > file_name.sh來創(chuàng)建的,則需要通過chmod +x file_name.sh或者chmod 755 file_name.sh來將其轉(zhuǎn)換成可執(zhí)行文件通過 shell 運(yùn)行的命令的返回值可以通過
exit命令來進(jìn)行設(shè)置,如果需要檢驗(yàn)命令是否成功運(yùn)行,可以通過echo $?的來查詢返回值來進(jìn)行判斷,返回值為0時(shí)代表命令執(zhí)行成功當(dāng)命令較長而將其分行放置可以更加便利的理解命令時(shí)可以通過
\來添加分隔,而連接一傳順序執(zhí)行的命令可以通過;來完成,如果命令之間存在邏輯關(guān)系,則可以用&&(AND) 或||(OR) 來代替;-
在 script 中進(jìn)行函數(shù)定義的語法如下:
function_name () { commands } -
在 shell 中完整的判斷語句語法如下,需要注意的是每一個(gè)
if代碼塊都需要用fi來結(jié)束#!/bin/bash echo "Enter the first number" read inp1 echo "Enter the second number" read inp2 echo "1. Addition" echo "2. Substraction" echo "3. Multiplication" echo "Please choose a word [1, 2 or 3]? " read oper if [ $oper -eq 1 ] then echo "Addition Result " $(($inp1 + $inp2)) else if [ $oper -eq 2 ] then echo "Substraction Result " $(($inp1 - $inp2)) else if [ $oper -eq 3 ] then echo "Multiplication Result " $(($inp1 * $inp2)) else echo "Invalid Input." fi fi fi類似的嵌套語句還可以通過
elif來完成:#!/bin/bash echo "Enter a number:" read count if [ $count -eq 100 ] then echo "The 'count' is 100" elif [ $count -gt 100 ] then echo "The 'count' is greater than 100" else echo "The 'count' is less than 100" fi 表達(dá)式:在 shell 中表達(dá)式可以通過
expr或let命令來定義,但一個(gè)比較推崇的書寫方式是$((...))字符串操作:在 bash script 中字符串的切片操作命令為
${string:0:n},統(tǒng)計(jì)字符串長度的命令為${#string}-
case statement: 當(dāng)變量的不同取值會(huì)使得命令的執(zhí)行有多個(gè)不同的途徑時(shí),一個(gè)更加簡潔的方法是通過
case語句來取代多重if-then-else-fi嵌套。在如下示例代碼中,每一個(gè)不同的字符串配對情形用pattern)來匹配,并且每一個(gè)情形的語句塊都要以;;來結(jié)束#!/bin/sh echo "Do you want to destroy your entire file system?" read response case "$response" in "yes") echo "I hope you know what you are doing!"; echo "I am supposed to type: rm -rf /"; echo "But I refuse to let you commit suicide";; "no") echo "You have some common sense! Aborting...";; "y" | "Y" | "YES") echo "I hope you konw what you are doing!"; echo "I am supposed to type: rm -rf /"; echo "But I refuse to let you commit suicide";; "n" | "N" | "NO") echo "You have some common sense! Aborting...";; *) echo "You have to give an answer!";; esac exit 0 -
for 循環(huán):Linux 下的
for循環(huán)語法及功能與 Python 中類似,都可以遍歷一個(gè)固定長度的列表中的數(shù)值,并對這些數(shù)值進(jìn)行操作,但在操作前后需要用do和done來完成#!/bin/sh sum=0 for j in 1 2 3 4 5 6 7 8 9 10 do sum=$(( ($sum+$j) )) done echo The sum is: $sum echo The sum of numbers from 1 to n is: 'n*(n+1)/2' echo Check Value = $(( ($j*($j+1))/2 )) exit 0for循環(huán)與case聯(lián)合使用的實(shí)例代碼如下:#!/bin/bash for filename in $(ls) do # Take extension available in a filename ext=${filename##*\.} case "$ext" in c) echo "$filename : C source file";; o) echo "$filename : Object file";; sh) echo "$filename : Shell script";; txt) echo "$filename : Text file";; *) echo "$filename : Unknown file type / Not processed";; esac done -
while & until 循環(huán):二者的判斷和執(zhí)行情況類似,但判斷條件設(shè)置上正好相反
#!/bin/bash n=$1 [ "$n" == "" ] && echo please give a number and try again && exit factorial=1 j=1 while [ $j -le $n ] # until [ $j -gt $n ] do factorial=$(( ($factorial * $j) )) j=$(( ($j+1) )) done echo The factorial of $n, "$n"'!' = $factorial exit 0 Debugging:在代碼調(diào)試階段可以通過
bash -x ./script_file以 debug 模式運(yùn)行 script,或者對于需要調(diào)試的代碼段用set -x和set +x命令包含起來臨時(shí)文件:可以采用
TEMP=$(mktemp /tmp/tempfile.XXXXXXXX)來創(chuàng)建臨時(shí)文件 和TEMPDIR=$(mktemp -d /tmp/tempdir.XXXXXXXX)來創(chuàng)建臨時(shí)目錄