最牛B的Linux Shell命令



引言

Shell作爲Unix系操作系統當中最有魅力且不可或缺的組件,經過數十載的洗禮不僅沒有被淘汰,而且愈加變得成熟穩健,究其原因,大概因爲它是個非常穩固的粘合劑,能夠把大量功能強大的組件任意配搭,總能很好很快地完成用戶的任務。

本文的一些命令很可能看起來是“雕蟲小技”,我們只好仰慕一下Shell大牛了,但是有些細節我會稍加發掘加以說明,遇到有趣的地方希望能博您一笑了。

1.以sudo運行上條命令

$ sudo !!

大家應該都知sudo,不解釋。但通常出現的情況是,敲完命令執行後報錯才發現忘了sudo。這時候,新手用戶就會:按上箭頭,按左箭頭,盯着光標回到開始處,輸入sudo,回車;高手用戶就蛋定多了,按Ctrl-p,按Ctrl-a,輸入sudo,回車。

這裏介紹這個是天外飛仙級別的,對,就直接sudo !!。

當然這幾種解決方式效果是完全一樣的,只是款不一樣,嗯,不解釋。

兩個感嘆號其實是bash的一個特性,稱爲事件引用符(event designators)。!!其實相當於!-1,引用前一條命令,當然也可以!-2,!-50。默認情況下bash會在~/.bash_history文件內記錄用戶執行的最近500條命令,history命令可以顯示這些命令。

關於事件引用符的更多用法可以深入閱讀The Definitive Guide to Bash Command Line History。

2.以HTTP方式共享當前文件夾的文件

$ python -m SimpleHTTPServer

這命令啓動了Python的SimpleHTTPServer模塊,考慮到Python在絕大多數的Linux發行版當中都默認安裝,所以這個命令很可能是最簡單的跨平臺傳文件的方法。

命令執行後將在本機8000端口開放HTTP服務,在其他能訪問本機的機器的瀏覽器打開ttp://ip:8000即打開一個目錄列表,點擊即可下載。

3.在以普通用戶打開的vim當中保存一個root用戶文件

:w !sudo tee %

這題目讀起來糾結,其實是很常見的,常常忘記了sudo就直接用vim編輯/etc內的文件,(不過也不一定,vim發現保存的文件無法保存時候會提示)等編輯好了,保存時候才發現沒權限。曲線方法是先保存個臨時文件,退出後再sudo cp回去。不過實際上在vim裏面可以直接完成這個過程的,命令就是如此。

查閱vim的文檔(輸入:help :w),會提到命令:w!{cmd},讓vim執行一個外部命令{cmd},然後把當前緩衝區的內容從stdin傳入。

tee是一個把stdin保存到文件的小工具。

而%,是vim當中一個只讀寄存器的名字,總保存着當前編輯文件的文件路徑。

所以執行這個命令,就相當於從vim外部修改了當前編輯的文件,好完工。

4.切換回上一個目錄

$ cd -

應該不少人都知道這個,橫杆-代表上一個目錄的路徑。

實際上cd -就是cd $OLDPWD的簡寫,bash的固定變量$OLDPWD總保存着之前一個目錄的路徑。

相對地,$PWD總保存着當前目錄的路徑。這些變量在編寫shell腳本時候相當有用。

5.替換上一條命令中的一個短語

$ ^foo^bar^

又是另外一個事件引用符(event designator),可以把上一條命令當中的foo替換成bar。

在需要重複運行調試一道長長的命令,需要測試某個參數時候,用這個命令會比較實用;但多數人會首先選擇按上箭頭提出上道命令,再移動光標去修改某參數,這樣更直觀,但效率上就不夠使用引用符高,而且在腳本中用這個方法可以簡化很多。

這道命令的原始樣式應該是這樣的:

!!:s/foo/bar/

本文一開始介紹過!!,後面的一段大家應該很熟悉,vim、sed的替換操作都是這樣的

6.快速備份一個文件

$ cp filename{,.bak}

這道命令把filename文件拷貝成filename.bak,大家應該在一些比較複雜的安裝教程裏面見過這樣的用法。其原理就在於bash對大括號的展開操作,filename{,.bak}這一段會被展開成filename filename.bak再傳給cp,於是就有了備份的命令了。

大括號在bash裏面是一個排列的意義,可以試試這個:

$ echo {a,b,c}{a,b,c}{a,b,c}

將輸出三個集合的全排列:

aaa aab aac aba abb abc aca acb acc
baa bab bac bba bbb bbc bca bcb bcc
caa cab cac cba cbb cbc cca ccb ccc
關於shell當中的集合操作,可深入閱讀“Set Operations in the Unix Shell”

7.免密碼ssh登錄主機

$ ssh-copy-id remote-machine

這個命令把當前用戶的公鑰串寫入到遠程主機的~/.ssh/authorized_keys內,這樣下次使用ssh登錄的時候,遠程主機就直接根據這串密鑰完成身份校驗,不再詢問密碼了。前提是你當前用戶有生成了公鑰,默認是沒有的,先執行ssh-keygen試試吧!

這個命令如果用手工完成,是這樣的:

your-machine$ scp ~/.ssh/identity.pub remote-machine:
your-machine$ ssh remote-machine
remote-machine$ cat identity.pub >> ~/.ssh/authorized_keys

如果你想刪掉遠程主機上的密鑰,直接打開authorized_keys,搜索你的用戶名,刪除那行,即可。

8.抓取Linux桌面的視頻
1
 $ ffmpeg -f x11grab -s wxga -r 25 -i :0.0 -sameq /tmp/out.mpg

我們在一些視頻網站上看到別人的3D桌面怎麼怎麼酷的視頻,通常就是這麼來的,ffmpeg可以直接解碼X11的圖形,並轉換到相應輸出格式。

ffmpeg的通常用法是,根據一堆參數,輸出一個文件,輸出文件通常放最後,下面解析下幾個參數:

-f x11grab 指定輸入類型。因爲x11的緩衝區不是普通的視頻文件可以偵測格式,必須指定後ffmpeg才知道如何獲得輸入。

-s wxga 設置抓取區域的大小。wxga是1366*768的標準說法,也可以換成-s 800×600的寫法。

-r 25 設置幀率,即每秒抓取的畫面數。

-i :0.0 設置輸入源,本地X默認在0.0

-sameq 保持跟輸入流一樣的圖像質量,以用來後期處理。

後記
說Shell是一種編程語言,可能有些尷尬,雖然很多人每天都在用Shell,但從來沒見它榮登TIOBE編程語言排行榜之類的,可以說毫無名分,因爲很多用戶沒意識到它是一種語言,只當做這是一個能夠很好完成任務的工具,基本得理所當然,就好像GUI程序的菜單、按鈕一樣。

掌握Shell,通常能夠讓任務在數秒鐘內完成,這就讓Shell跟C、Perl、Python這些語言區別開來,沒人否認後者更能勝任更多的任務,但是他們是在不同的層面上去做,Shell依賴大量的系統組件黏合調用,而後者依賴各種庫,各所擅長不同的應用領域,比喻就是,Shell是混凝土,可以很方便地粘合一些建築組件而成爲穩固的高樓大廈;但同樣是粘合劑,粘玻璃窗、粘書報、粘皮鞋,混凝土是絕對不合適的,Shell並不擅長一些細緻操作,比如它連浮點運算都不支持,更別提什麼圖形運算什麼的。但這並不妨礙Shell來幫我們完成很多粗重任務。

Shell的工作方式,大多數入門用戶會覺得枯燥難學,而所謂的經典教材也離不開《Advanced Bash-Scripting》、《Bash Guide for Beginners》,但類似本文這樣的一些“雕蟲小技”因爲難登大雅之堂絕不會收錄進去。這情況如果象國外一些unix用戶比較多的地方會有很好改善,即使是新手,偶爾看看別人的操作都能“偷師”一手,我編譯本系列文章其實也就希望稍微改善一下這個狀況。

1.用你最喜歡的編輯器來敲命令

command <CTRL-x CTRL-e>

在已經敲完的命令後按<CTRL-x CTRL-e>,會打開一個你指定的編輯器(比如vim,通過環境變量$EDITOR指定),裏面就是你剛輸入的命令,然後愛怎麼編輯就怎麼編輯吧,特別是那些參數異常複雜的程序,比如mencoder/ffmpeg,一個命令動輒3、4行的,要修改其中的參數,這個方法最合適不過了,保存退出後自動執行這個程序。

實際上這是readline庫的功能,在默認情況下,bash使用的是emacs模式的命令行操作方式,<CTRL-x CTRL-e>是調用這個功能的一個綁定。如果你習慣使用vi模式,按<ESC v>可以實現同樣功能。

如果你喜歡別的編輯器,可以在~/.bashrc裏面放上比如export EDITOR=nano的命令。

另外一個修改命令的方法是使用fc命令(Fix Command),在編輯器裏面打開上一句命令。我們的第一輯連載提過一個^foo^bar^命令可以用fc來實現:fc -s foo=bar。

2.清空或創建一個文件

> file.txt

>在shell裏面是標準輸出重定向符,即把(前部個命令的)命令行輸出轉往一個文件內,但這裏沒有“前部命令”,輸出爲空,於是就覆蓋(或創建)成一個空文件了。

有些腳本的寫法是:>file.txt,因爲:是bash默認存在的空函數。

單純創建文件也可以用$touch file.txt,touch本來是用作修改文件的時間戳,但如果文件不存在,就自動創建了。

3.用ssh創建端口轉發通道

 ssh -N -L2001:remotehost:80 user@somemachine

這個命令在本機打開了2001端口,對本機2001端口的請求通過somemachine作爲跳板,轉到remotehost的80端口上。

實現效果跟術語反向代理是相似的,實際上就是端口轉發,注意上面的描述涉及了3臺主機,但當然somemachine可以變成localhost。

這個命令比較抽象,但有時候是很有用的,比如因爲衆所周知的原因國內的IP的80端口無法使用,又或者公司的防火牆只給外網開了ssh端口,需要訪問內部服務器一個web應用,以及需要訪問某些限定了來源IP的服務,就可以用上這個方法了。

舉一個具體例子,運行:

ssh -f -N -L 0.0.0.0:443:twitter.com:443 shell.cjb.net
ssh -f -N -L 0.0.0.0:80:twitter.com:80 shell.cjb.net

然後在/etc/hosts裏面添加127.0.0.1 twitter.com,好吧剩下的你懂的。

當然通常做這個功能的反向代理,應該要用squid、nginx之類,ssh就算是輕量級的嘗試吧!

4.重置終端

 reset

如果你試過不小心cat了某個二進制文件,很可能整個終端就傻掉了,可能不會換行,沒法回顯,大堆亂碼之類的,這時候敲入reset回車,不管命令有沒有顯示,就能回覆正常了。

實際上reset命令只是輸出了一些特殊字符,我們看BusyBox裏面最簡單的reset程序的實現:

 printf("\033c\033(K\033[J\033[0m\033[?25h");

輸出的這些字符對Shell是有特殊意義的:

\033c: “ESC c” – 發送重置命令;
\033(K: “ESC ( K” – 重載終端的字符映射;
\033[J: “ESC [ J” – 清空終端內容;
\033[0m: “ESC [ 0 m” – 初始化字符顯示屬性;
\033[?25h: “ESC [ ? 25 h” – 讓光標可見;
其中字符顯示屬性經常用來設定打印字符的顏色等,可參考這個博文。

5.在午夜的時候執行某命令

echo cmd | at midnight

說的就是at這個組件,通常跟cron相提並論,不過at主要用於定時一次性任務,而cron定時週期性任務。

at的參數比較人性化,跟英語語法一樣,可以tomorrow, next week之類的,詳細的查看手冊man at。

6.遠程傳送麥克風語音

dd if=/dev/dsp | ssh username@host dd of=/dev/dsp

沒錯就是實現一個喊話器的功能。

/dev/dsp是Linux下聲卡的文件映射(Digital Signal Proccessor),從其中讀數據就是錄音,往裏面寫數據就是播放,相當簡單!

dd是常用的數據拷貝程序,如果不同時指定if、of,就直接使用stdin/stdout來傳輸。

如果你沒有遠程主機,可以試試這樣:

dd if=/dev/dsp of=/dev/dsp

直接回放麥克風的聲音,只是有一點延時。

但是如果有別的程序正在使用聲卡,這個方法就不湊效了,因爲一般的聲卡都不允許多個音頻流同時處理,可以借用alsa組件的工具,arecord跟aplay:

arecord | ssh username@host aplay

本地回放就是:

arecord | aplay

如果你想嚇嚇別人:

 cat /dev/urandom | ssh username@host aplay

7.映射一個內存目錄

mount -t tmpfs -o size=1024m tmpfs /mnt/ram

這個命令開了一塊1G內存來當目錄用。不過放心,如果裏面沒文件,是不會佔用內存的,用多少佔多少。

不過一般來說沒必要手動掛載,因爲多數發行版都會在fstab內預留了一個內存目錄,掛載在/dev/shm,直接使用即可;

最常見的用途是用內存空間來放Firefox的配置,可以讓慢吞吞的FF快很多,參見Shellex的博文:用tmpfs讓Firefox在內存中飛馳,以及後來的改進:用tmpfs讓Firefox在內存中飛馳II,其中提到的腳本來自speeding up firefox with tmpfs and automatic rsync。

那個破爛LinuxQQ也可以用這個方法,減少因爲大量磁盤IO導致的問題。

8.用diff對比遠程文件跟本地文件

 ssh user@host cat /path/to/remotefile | diff /path/to/localfile -

diff通常的用法是從參數讀入兩個文件,而命令裏面的-則是指從stdin讀入了。

善用ssh可以讓web開發減少很多繁瑣,還有比如sshfs,可以從編輯-上傳-編輯-上傳的人工循環裏面解脫出來。

9.查看系統中佔用端口的進程

 netstat -tulnp

Netstat是很常用的用來查看Linux網絡系統的工具之一,這個參數可以背下來:

-t: 顯示TCP鏈接信息
-u: 顯示UDP鏈接信息
-l: 顯示監聽狀態的端口
-n: 直接顯示ip,不做名稱轉換
-p: 顯示相應的進程PID以及名稱(要root權限)
如果要查看關於sockets更詳細佔用信息等,可以使用lsof工具。

1. 更友好的顯示當前掛載的文件系統

 mount | column -t
 

這條命令適用於任何文件系統,column 用於把輸出結果進行列表格式化操作,這裏最主要的目的是讓大家熟悉一下 columnt 的用法。

下面是單單使用 mount 命令的結果:

 $ mount
 
/dev/root on / type ext3 (rw)
/proc on /proc type proc (rw)
/dev/mapper/lvmraid-home on /home type ext3 (rw,noatime)
 

而加了 column -t 命令後就成爲這樣了:

 $ mount | column -t
 
/dev/root on / type ext3 (rw)
/proc on /proc type proc (rw)
/dev/mapper/lvmraid-home on /home type ext3 (rw,noatime)
 

另外你可加上列名稱來改善輸出結果

 $ (echo "DEVICE - PATH - TYPE FLAGS" && mount) | column -t
 
DEVICE                    -   PATH   -     TYPE   FLAGS
/dev/root                 on  /      type  ext3   (rw)
/proc                     on  /proc  type  proc   (rw)
/dev/mapper/lvmraid-home  on  /home  type  ext3   (rw,noatime)
 

列2和列4並不是很友好,我們可以用 awk 來再處理一下

 $ (echo "DEVICE PATH TYPE FLAGS" && mount | awk '$2=$4="";1') | column -t
 
DEVICE                    PATH   TYPE   FLAGS
/dev/root                 /      ext3   (rw)
/proc                     /proc  proc   (rw)
/dev/mapper/lvmraid-home  /home  ext3   (rw,noatime)
 

最後我們可以設置一個別名,爲 nicemount

 $ nicemount() { (echo "DEVICE PATH TYPE FLAGS" && mount | awk '$2=$4="";1') | column -t; }
 

試一下

 $ nicemount
 
DEVICE                    PATH   TYPE   FLAGS
/dev/root                 /      ext3   (rw)
/proc                     /proc  proc   (rw)
/dev/mapper/lvmraid-home  /home  ext3   (rw,noatime)
 

2. 運行前一個 Shell 命令,同時用 “bar” 替換掉命令行中的每一個 “foo”

 !!:gs/foo/bar
 


!! 表示重複執行上一條命令,並用 :gs/foo/bar 進行替換操作。

關於 !! 這個用法在前一篇文章中已有詳細的介紹。

3. 實時某個目錄下查看最新改動過的文件

 watch -d -n 1 'df; ls -FlAt /path'
 

watch 是實時監控工具,-d 參數會高亮顯示變��的區域,-n 1 參數表示刷新間隔爲 1 秒。

df; ls -FlAt /path 運行了兩條命令,df 是輸出磁盤使用情況,ls -FlAt 則列出 /path 下面的所有文件。

ls -FlAt 的參數詳解:
•-F 在文件後面加一個文件符號表示文件類型,共有 /=>@| 這幾種類型, 表示可執行文件,/ 表示目錄,= 表示接口( sockets) ,> 表示門, @ 表示符號鏈接, | 表示管道。
•-l 以列表方式顯示
•-A 顯示 . 和 ..
•-t 根據時間排序文件

4. 通過 SSH 掛載遠程主機上的文件夾

 sshfs name@server:/path/to/folder /path/to/mount/point
 

這條命令可以讓你通過 SSH 加載遠程主機上的文件系統爲本地磁盤,前提是你需要安裝 FUSE 及 sshfs 這兩個軟件。

譯者注:關於 sshfs 實際上我之前寫過一篇文章介紹過,詳見在 Ubuntu 上使用 sshfs 映射遠程 ssh 文件系統爲本地磁盤。

卸載的話使用 fusermount 或 umount 命令:

 $ fusermount -u /path/to/mount/point
# umount /path/to/mount/point
 

5. 通過 DNS 來讀取 Wikipedia 的詞條

 dig +short txt <keyword>.wp.dg.cx
 

這也許是最有趣的一條技巧了,David Leadbeater 創建了一個 DNS 服務器,通過它當你查詢一個 TXT 記錄類型時,會返回一條來自於 Wikipedia 的簡短的詞條文字,這是他的介紹。

這裏有一個樣例,來查詢 “hacker” 的含義:

 $ dig +short txt hacker.wp.dg.cx
 
"Hacker may refer to: Hacker (computer security), someone involved
in computer security/insecurity, Hacker (programmer subculture), a
programmer subculture originating in the US academia in the 1960s,
which is nowadays mainly notable for the free software/” “open
source movement, Hacker (hobbyist), an enthusiastic home computer
hobbyist http://a.vu/w:Hacker"
 

這裏使用了 dig 命令,這是標準的用來查詢 DNS 的系統管理工具,+short 參數是讓其僅僅返回文字響應,txt 則是指定查詢 TXT 記錄類型。

更簡單的做法是你可以爲這個技巧創建一個函數:

 wiki() { dig +short txt $1.wp.dg.cx; }
#然後試試吧:
wiki hacker
 
"Hacker may refer to: Hacker (computer security), …"
 

如果你不想用 dig ,也可以用 host 命令:

 host -t txt hacker.wp.dg.cx
 

另外在Twitter上看過某人的創意,用普通的dns來作爲程序版本更新的查詢服務器:設定域名software-version-check.example.com的A記錄爲1.2.40.3,對比自己的版本號,嗯,有更新了!

6. 用 Wget 的遞歸方式下載整個網站

 wget --random-wait -r -p -e robots=off -U Mozilla www.example.com
 

參數解釋:
–random-wait 等待 0.5 到 1.5 秒的時間來進行下一次請求
-r 開啓遞歸檢索
-e robots=off 忽略 robots.txt
-U Mozilla 設置 User-Agent 頭爲 Mozilla

其它一些有用的參數:
•–limit-rate=20K 限制下載速度爲 20K
•-o logfile.txt 記錄下載日誌
•-l 0 刪除深度(默認爲5)
•-wait=1h 每下載一個文件後等待1小時

7. 複製最後使用的命令中的參數

 <ALT + .> or <ESC + .>
 

這個快捷鍵只能工作於 shell 的 emacs 編輯模式,它可以從最後使用的命令行中複製參數到當前命令行中,下面是一個樣例:

 $ echo a b c
a b c
 
$ echo <Press ALT + .>
$ echo c
 

你可以重複執行該快捷鍵,以便獲取自已需要的參數,

以下是樣例:

 $ echo 1 2 3
1 2 3
$ echo a b c
a b c
 
$ echo <Press ALT + .>
$ echo c
 
$ echo <Press ALT + .> again
$ echo 3
 

另外,假如你想指定第1個或第2個,或者是第 n 個參數的話,可以按 ALT + 1 (或 ESC + 1) 或 ALT + 2 (或 ESC +2) 這樣形式的快捷鍵。

以下是樣例:

 $ echo a b c
a b c
 
$ echo <Press ALT + 1> <Press ALT + .>
$ echo a
a
 
$ echo <Press ALT + 2> <Press ALT + .>
$ echo b
b
 

查看Emacs Editing Mode Keyboard Shortcuts一文獲取更多類似的快捷鍵。

8. 執行一條命令但不保存到 history 中

 $ <space>command
 

這條命令可運行於最新的 Bash shell 裏,在其它 shell 中沒測試過。

通過在命令行前面添加一個空格,就可以阻止這條命令被保存到 bash history (~/.bash_history) 文件中,這個行爲可以通過 $HISTIGNORE shell 變量來控制。我的設置是 HISTIGNORE=”&:[ ]*” ,表示不保存重複的命令到 history 中,並且不保存以空格開頭的命令行。$HISTIGNORE 中的值以冒號分隔。

如果你的命令內包含密碼,比如mysqladmin,不把它記錄在歷史當中是好主義。

深入瞭解的話,可進一步看此文The Definitive Guide to Bash Command Line History

9. 顯示當前目錄中所有子目錄的大小

 du -h --max-depth=1
 

–max-depth=1 參數可以讓 du 命令顯示當前目錄下 1 級子目錄的統計信息,當然你也可以把 1 改爲 2 ,進一步顯示 2 級子目錄的統計信息,可以靈活運用。而 -h 參數則是以 Mb 、G 這樣的單位來顯示大小。

譯者注:在此推薦一個小工具 ncdu ,可以更方便的達到此效果。

10. 顯示消耗內存最多的 10 個運行中的進程,以內存使用量排序

 ps aux | sort -nk +4 | tail
 

顯然這並不是最好的方法,但它確實用起還不錯。

這是一個典型的管道應用,通過 ps aux 來輸出到 sort 命令,並用 sort 排序列出 4 欄,再進一步轉到 tail 命令,最終輸出 10 行顯示使用內存最多的進程情況。

假如想要發現哪個進程使用了大量內存的話,我通常會使用 htop 或 top 而非 ps 。

11. 用 python 快速開啓一個 SMTP 服務

 python -m smtpd -n -c DebuggingServer localhost:1025
 

這是一個用 Python 標準庫 smtpd (用 -m smtpd 指定) 實現在簡易 SMTP 服務,運行於 1025 端口 。

另外三個參數的解釋:
-n 參數讓 Python 不要進行 setuid ( 改變用戶)爲 “nobody” ,也就是說直接用你的帳號來運行
-c DebuggingServer 參數是讓 Python 運行時在屏幕上輸出調試及運行信息
* localhost:1025 參數則是讓 Python 在本地的 1025 端口上開啓 SMTP 服務

另外,假如你想讓程序運行於標準的 25 的端口上的話,你必須使用 sudo 命令,因爲只有 root 才能在 1-1024 端口上開啓服務。如下:

 sudo python -m smtpd -n -c DebuggingServer localhost:25
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章