04 環境變量與文件查找

介紹環境變量的作用與用法,及幾種搜索文件的方法。學會這些技巧可以高效地使用 Linux 。

 一、環境變量

1. 變量

變量是什麼,準確的說應該是 Shell 變量,所謂變量就是計算機中用於記錄一個值(不一定是數值,也可以是字符或字符串)的符號,而這些符號將用於不同的運算處理中。通常變量與值是一對一的關係,可以通過表達式讀取它的值並賦值給其它變量,也可以直接指定數值賦值給任意變量。爲了便於運算和處理,大部分的編程語言會區分變量的類型,用於分別記錄數值、字符或者字符串等等數據類型。Shell 中的變量也基本如此,有不同類型(但不用專門指定類型名),可以參與運算,有作用域限定。

變量的作用域即變量的有效範圍(比如一個函數中、一個源文件中或者全局範圍),在該範圍內只能有一個同名變量。一旦離開則該變量無效,如同不存在這個變量一般。

 在 Shell 中如何創建一個變量,如何給變量賦值和如何讀取變量的值呢?

舉例:使用 declare 命令創建一個變量名爲 tmp 的變量(tmp爲 temporary 的縮寫,意爲臨時的、暫時的),並使用 = 號賦值運算符,將變量 tmp 賦值爲 value

$ declare tmp
$ tmp=value  # value是賦值給變量的值,如果value不包含任何空白字符(如空格),則不要使用引號進行引用,反之則必須使用單引號或雙引號。
注: var = value不同於 val=value,前者是相等操作,後者是賦值操作。

$ declare tmp
$ tmp="v a lue" #必須使用引號

#或者在聲明的同時一起賦值
$ declare tmp=value

其實,腳本語言通常不需要在使用變量之前聲明其類型,只需要直接賦值就可以了。在Bash中,每一個變量的值都是字符串,都是以字符串的形式存儲。 

$ tmp=value

讀取變量的值,使用 echo 命令和 $ 符號($ 符號用於表示引用一個變量的值,初學者經常忘記輸入):

$ echo $tmp
value

$ echo tmp
tmp

 注意:並不是任何形式的變量名都是可用的,變量名只能是英文字母、數字或者下劃線,且不能以數字作爲開頭

2. 環境變量

環境變量:被shell環境或操作系統用來存儲一些特別的值的特殊的變量。

環境變量:是一個具有特定名字的對象,它包含了一個或者多個應用程序所將使用到的信息。

環境變量:是未在當前進程中定義,而從父進程中繼承而來的變量。

Linux是一個多用戶的操作系統。每個用戶登錄系統後,都會有一個專用的運行環境。通常每個用戶默認的環境都是相同的,這個默認環境實際上就是一組環境變量的定義。用戶可以對自己的運行環境進行定製,其方法就是修改相應的系統環境變量。Linux下的環境變量是一種全局變量,存在所有的shell中,在登錄的時候就有系統定義的環境變量了。Linux的環境變量具有繼承性,即shell會繼承父shell的環境變量。 

                          

通常我們會涉及到的變量類型有三種:

  • 當前 Shell 進程私有用戶自定義變量,如上面我們創建的 tmp 變量,只在當前 Shell 中有效。
  • Shell 本身內建的變量。
  • 從自定義變量導出的環境變量。

也有三個與上述三種環境變量相關的命令:setenvexport。這三個命令很相似,都是用於打印環境變量信息,區別在於涉及的變量範圍不同。詳見下表:

命 令 說 明
set 顯示當前 Shell 所有變量,包括其內建環境變量(與 Shell 外觀等相關),用戶自定義變量及導出的環境變量。
env 顯示與當前用戶相關的環境變量,還可以讓命令在指定環境中運行。
export 顯示從 Shell 中導出成環境變量的變量,也能通過它將自定義變量導出爲環境變量。

關於哪些變量是環境變量,可以簡單地理解成在當前進程的子進程有效則爲環境變量,否則不是(有些人也將所有變量統稱爲環境變量,只是以全局環境變量和局部環境變量進行區分,我們只要理解它們的實質區別即可)。我們這裏用 export 命令來體會一下,先在 Shell 中設置一個變量 temp=shiyanlou,然後再新創建一個子 Shell 查看 temp 變量的值:

此處輸入圖片的描述

注意:爲了與普通變量區分,通常我們習慣將環境變量名設爲大寫。

永久生效

但是問題來了,當你關機後,或者關閉當前的 shell 之後,環境變量就沒了啊。怎麼才能讓環境變量永久生效呢?

按變量的生存週期來劃分,Linux 變量可分爲兩類:

  1. 永久的:需要修改配置文件,變量永久生效;

  2. 臨時的:使用 export 命令行聲明即可,變量在關閉 shell 時失效。

這裏介紹兩個重要文件 /etc/bashrc(有的 Linux 沒有這個文件) 和 /etc/profile ,它們分別存放的是 shell 變量和環境變量。

這個 .profile 只對當前用戶永久生效。而寫在 /etc/profile裏面的是對所有用戶永久生效,所以如果想要添加一個永久生效的環境變量,只需要打開 /etc/profile,在最後加上你想添加的環境變量就好啦。

例如:編輯/etc/profile文件,添加CLASSPATH變量
          # vim  /etc/profile
          添加一行:
          export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib

 修改後需要執行重新登錄才能生效,也可以執行命令source /etc/profile來立即生效

 二、命令的查找路徑與順序

我們在 Shell 中輸入一個命令,Shell 是怎麼知道去哪找到這個命令然後執行的呢?這是通過環境變量 PATH 來進行搜索的,熟悉 Windows 的用戶可能知道 Windows 中的也是有這麼一個 PATH 環境變量。這個 PATH裏面就保存了 Shell 中執行的命令的搜索路徑。

查看 PATH 環境變量的內容:

$ echo $PATH

默認情況下會看到如下輸出:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

通常這一類目錄下放的都是可執行文件,當我們在 Shell 中執行一個命令時,系統就會按照 PATH 中設定的路徑按照順序依次到目錄中去查找,如果存在同名的命令,則執行先找到的那個。

舉例:創建一個最簡單的可執行 Shell 腳本和一個使用 C 語言創建的“ hello world ”程序。

創建一個 Shell 腳本文件:

$ gedit hello_shell.sh

在腳本中添加如下內容,保存並退出(注意不要省掉第一行,這不是註釋,出現語法錯誤,就是因爲沒有了第一行):

#!/bin/bash

for ((i=0; i<10; i++));do
    echo "hello shell"
done

exit 0

爲文件添加可執行權限:

$ chmod 755 hello_shell.sh

執行腳本:

$ ./hello_shell.sh

創建一個 C 語言“ hello world ”程序:

$ gedit hello_world.c
#include <stdio.h>

int main(void)
{
    printf("hello world!\n");
    return 0;
}

保存後使用 gcc 生成可執行文件:

$ gcc -o hello_world hello_world.c

gcc 生成二進制文件默認具有可執行權限,不需要修改

/home/shiyanlou 家目錄創建一個 mybin 目錄,並將上述 hello_shell.sh hello_world 文件移動到其中:

$ mkdir mybin
$ mv hello_shell.sh hello_world mybin/

現在可以在 mybin 目錄中分別運行剛剛創建的兩個程序:

$ cd mybin
$ ./hello_world
#輸出結果
hello world! 

$ ./hello_shell.sh
#輸出結果
hello shell
hello shell
hello shell
hello shell
hello shell
hello shell
hello shell
hello shell
hello shell
hello shell

回到上一級目錄,也就是 shiyanlou 家目錄,當再想運行那兩個程序時,會發現提示命令找不到,除非加上命令的完整路徑,但那樣很不方便,如何做到像使用系統命令一樣執行自己創建的腳本文件或者程序呢?那就要將命令所在路徑添加到 PATH 環境變量了。

三、添加自定義路徑到“PATH”環境變量

應該注意到 PATH 裏面的路徑是以 : 作爲分割符的,所以我們可以這樣添加自定義路徑:

$ PATH=$PATH:/home/shiyanlou/mybin

注意這裏一定要使用絕對路徑。

現在你就可以在任意目錄執行那兩個命令了(注意需要去掉前面的 ./)。

你可能會意識到這樣並沒有很好的解決問題,因爲我給 PATH 環境變量追加了一個路徑,它也只是在當前 Shell 有效,我一旦退出終端,再打開就會發現又失效了。有沒有方法讓添加的環境變量全局有效?或者每次啓動 Shell 時自動執行上面添加自定義路徑到 PATH 的命令?下面我們就來說說後一種方式——讓它自動執行。

在每個用戶的 home 目錄中有一個 Shell 每次啓動時會默認執行的一個配置腳本,以初始化環境,包括添加一些用戶自定義環境變量等等。zsh 的配置文件是 .zshrc,相應 Bash 的配置文件爲 .bashrc 。它們在 etc 下還都有一個或多個全局的配置文件,不過我們一般只修改用戶目錄下的配置文件。

我們可以簡單地使用下面命令直接添加內容到 .zshrc 中:

$ echo "PATH=$PATH:/home/shiyanlou/mybin" >> .zshrc

上述命令中 >> 表示將標準輸出以追加的方式重定向到一個文件中,注意 > 是以覆蓋的方式重定向到一個文件中,使用的時候一定要注意分辨。在指定文件不存在的情況下都會創建新的文件。

四、刪除和修改已有變量

4.1 變量修改

變量的修改有以下幾種方式:

變量設置方式 說明
${變量名#匹配字串} 從頭向後開始匹配,刪除符合匹配字串的最短數據
${變量名##匹配字串} 從頭向後開始匹配,刪除符合匹配字串的最長數據
${變量名%匹配字串} 從尾向前開始匹配,刪除符合匹配字串的最短數據
${變量名%%匹配字串} 從尾向前開始匹配,刪除符合匹配字串的最長數據
${變量名/舊的字串/新的字串} 將符合舊字串的第一個字串替換爲新的字串
${變量名//舊的字串/新的字串} 將符合舊字串的全部字串替換爲新的字串

比如要修改我們前面添加到 PATH 的環境變量。爲了避免操作失誤導致命令找不到,我們先將 PATH 賦值給一個新的自定義變量 path:

$ path=$PATH
$ echo $path
$ path=${path%/home/shiyanlou/mybin}
# 或使用通配符,*表示任意多個任意字符
$ path=${path%*/mybin}

4.2 變量刪除

可以使用 unset 命令刪除一個環境變量:

$ unset temp

五、如何讓環境變量立即生效

前面我們在 Shell 中修改了一個配置腳本文件之後(比如 zsh 的配置文件 home 目錄下的 .zshrc),每次都要退出終端重新打開甚至重啓主機之後其才能生效,很是麻煩,我們可以使用 source 命令來讓其立即生效,如:

$ source .zshrc

source 命令還有一個別名就是 .,注意與表示當前路徑的那個點區分開,雖然形式不一樣,但作用和使用方式一樣,上面的命令如果替換成 . 的方式就該是:

$ . ./.zshrc

注意第一個點後面有一個空格,而且後面的文件必須指定完整的絕對或相對路徑名,source 則不需要。

六、搜索文件

與搜索相關的命令常用的有 whereiswhichfind  locate 。

  • whereis 簡單快速
$ whereis who

此處輸入圖片的描述

你會看到它找到了三個路徑,兩個可執行文件路徑和一個 man 在線幫助文件所在路徑,這個搜索很快,因爲它並沒有從硬盤中依次查找,而是直接從數據庫中查詢。whereis 只能搜索二進制文件(-b),man 幫助文件(-m)和源代碼文件(-s)。如果想要獲得更全面的搜索結果可以使用 locate 命令。

  • locate 快而全

通過“ /var/lib/mlocate/mlocate.db ”數據庫查找,不過這個數據庫也不是實時更新的,系統會使用定時任務每天自動執行 updatedb 命令更新一次,所以有時候你剛添加的文件,它可能會找不到,需要手動執行一次 updatedb 命令。它可以用來查找指定目錄下的不同文件類型,如查找 /etc 下所有以 sh 開頭的文件:

$ sudo apt-get install locate
$ locate /etc/sh

注意,它不只是在 /etc 目錄下查找,還會自動遞歸子目錄進行查找。

查找 /usr/share/ 下所有 jpg 文件:

$ locate /usr/share/\*.jpg

注意要添加 * 號前面的反斜槓轉義,否則會無法找到。

如果想只統計數目可以加上 -c 參數,-i 參數可以忽略大小寫進行查找,whereis 的 -b-m-s 同樣可以使用。

  • which 小而精

which 本身是 Shell 內建的一個命令,我們通常使用 which來確定是否安裝了某個指定的軟件,因爲它只從 PATH 環境變量指定的路徑中去搜索命令:

$ which man
  • find 精而細

find 應該是這幾個命令中最強大的了,它不但可以通過文件類型、文件名進行查找而且可以根據文件的屬性(如文件的時間戳,文件的權限等)進行搜索。find 命令強大到,要把它講明白至少需要單獨好幾節課程纔行,我們這裏只介紹一些常用的內容。

這條命令表示去 /etc/ 目錄下面 ,搜索名字叫做 interfaces 的文件或者目錄。這是 find 命令最常見的格式,千萬記住 find 的第一個參數是要搜索的地方:

$ sudo find /etc/ -name interfaces

注意 find 命令的路徑是作爲第一個參數的, 基本命令格式爲 find [path] [option] [action] 。

與時間相關的命令參數:

參數 說明
-atime 最後訪問時間
-ctime 最後修改文件內容的時間
-mtime 最後修改文件屬性的時間

下面以 -mtime 參數舉例:

  • -mtime n:n 爲數字,表示爲在 n 天之前的“一天之內”修改過的文件
  • -mtime +n:列出在 n 天之前(不包含 n 天本身)被修改過的文件
  • -mtime -n:列出在 n 天之內(包含 n 天本身)被修改過的文件
  • -newer file:file 爲一個已存在的文件,列出比 file 還要新的文件名

列出 home 目錄中,當天(24 小時之內)有改動的文件:

$ find ~ -mtime 0

列出用戶家目錄下比 Code 文件夾新的文件:

$ find ~ -newer /home/shiyanlou/Code

 

 

 

 

 

 

 

 

 

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