首頁>技術>

-----------

我個人很喜歡使用 Linux 系統,雖然說 Windows 的圖形化介面做的確實比 Linux 好,但是對指令碼的支援太差了。一開始有點不習慣命令列操作,但是熟悉了之後反而發現移動滑鼠點點點才是浪費時間的罪魁禍首。。。

那麼對於 Linux 命令列,本文不是介紹某些命令的用法,而是說明一些簡單卻特別容易讓人迷惑的細節問題

1、標準輸入和命令引數的區別。

2、在後臺執行命令在退出終端後也全部退出了。

3、單引號和雙引號表示字串的區別。

4、有的命令和sudo一起用就 command not found。

一、標準輸入和引數的區別

這個問題一定是最容易讓人迷惑的,具體來說,就是搞不清什麼時候用管道符|和檔案重定向>,<,什麼時候用變數$。

比如說,我現在有個自動連線寬頻的 shell 指令碼connect.sh,存在我的家目錄:

$ where connect.sh | rm

實際上,這樣操作是錯誤的,正確的做法應該是這樣的:

$ rm $(where connect.sh)

前者試圖將where的結果連線到rm的標準輸入,後者試圖將結果作為命令列引數傳入。

標準輸入就是程式語言中諸如scanf或者readline這種命令;而引數是指程式的main函式傳入的args字元陣列

前文「Linux檔案描述符」說過,管道符和重定向符是將資料作為程式的標準輸入,而$(cmd)是讀取cmd命令輸出的資料作為引數。

$ cat filename...file text...$ cat < filename...file text...$ echo 'hello world' | cathello world

如果命令能夠讓終端阻塞,說明該命令接收標準輸入,反之就是不接受,比如你只執行cat命令不加任何引數,終端就會阻塞,等待你輸入字串並回顯相同的字串。

二、後臺執行程式

比如說你遠端登入到伺服器上,執行一個 Django web 程式:

$ python manager.py runserver 0.0.0.0Listening on 0.0.0.0:8080...

現在你可以透過伺服器的 IP 地址測試 Django 服務,但是終端此時就阻塞了,你輸入什麼都不響應,除非輸入 Ctrl-C 或者 Ctrl-/ 終止 python 程序。

可以在命令之後加一個&符號,這樣命令列不會阻塞,可以響應你後續輸入的命令,但是如果你退出伺服器的登入,就不能訪問該網頁了。

如果你想在退出伺服器之後仍然能夠訪問 web 服務,應該這樣寫命令 (cmd &):

$ (python manager.py runserver 0.0.0.0 &)Listening on 0.0.0.0:8080...$ logout

底層原理是這樣的

每一個命令列終端都是一個 shell 程序,你在這個終端裡執行的程式實際上都是這個 shell 程序分出來的子程序。正常情況下,shell 程序會阻塞,等待子程序退出才重新接收你輸入的新的命令。加上&號,只是讓 shell 程序不再阻塞,可以繼續響應你的新命令。但是無論如何,你如果關掉了這個 shell 命令列埠,依附於它的所有子程序都會退出。

而(cmd &)這樣執行命令,則是將cmd命令掛到一個systemd系統守護程序名下,認systemd做爸爸,這樣當你退出當前終端時,對於剛才的cmd命令就完全沒有影響了。

類似的,還有一種後臺執行常用的做法是這樣:

$ nohub some_cmd &

nohub命令也是類似的原理,不過透過我的測試,還是(cmd &)這種形式更加穩定。

三、單引號和雙引號的區別

不同的 shell 行為會有細微區別,但有一點是確定的,對於$,(,)這幾個符號,單引號包圍的字串不會做任何轉義,雙引號包圍的字串會轉義

shell 的行為可以測試,使用set -x命令,會開啟 shell 的命令回顯,你可以透過回顯觀察 shell 到底在執行什麼命令:

可見 echo $(cmd) 和 echo "$(cmd)",結果差不多,但是仍然有區別。注意觀察,雙引號轉義完成的結果會自動增加單引號,而前者不會。

也就是說,如果 $ 讀取出的引數字串包含空格,應該用雙引號括起來,否則就會出錯

四、sudo 找不到命令

有時候我們普通使用者可以用的命令,用 sudo 加許可權之後卻報錯 command not found:

$ connect.shnetwork-manager: Permission denied​$ sudo connect.shsudo: command not found

原因在於,connect.sh 這個指令碼僅存在於該使用者的環境變數中:

$ where connect.sh /home/fdl/bin/connect.sh

當使用 sudo 時,系統會使用 /etc/sudoers 這個檔案中規定的該使用者的許可權和環境變數,而這個指令碼在 /etc/sudoers 環境變數目錄中當然是找不到的。

解決方法是使用指令碼檔案的路徑,而不是僅僅透過指令碼名稱:

$ sudo /home/fdl/bin/connect.sh

8
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 我用四個命令概括了 Git 的所有套路