在之前的該系列的部分中,和是如何工作的。你在這些文章中學習的大多數內容都可應用於檔案,除了如何讓一個檔案變成可執行檔案。
因此讓我們在開始之前先解決這個問題。
在其他作業系統中,一個檔案的性質通常由它的字尾決定。如果一個檔案有一個 .jpg 擴充套件,作業系統會認為它是一幅影象;如果它以 .wav 結尾,它是一個音訊檔;如果它在檔名末尾以 .exe 結尾,它就是一個你可以執行的程式。
這導致了嚴重的問題,比如說木馬可以偽裝成文件檔案。幸運的是,在 Linux 下事物不是這樣執行的。可以確定的是,你可能會看到有些可執行檔案是以 .sh 結尾暗示它們是可執行的指令碼,但是這大部分是為了便於人眼找到檔案,就像你使用 ls --color
將可執行檔案的名字以亮綠色顯示的方式相同。
事實上大多數應用根本沒有擴充套件名。決定一個檔案是否是一個真正程式的是 x
(指可執行的)位。你可以通過執行以下命令使任何檔案變得可執行,
chmod a+x some_program
而不管它的擴充套件名是什麼或者是否存在。在上面命令中的 x
設定了 x
位,a
說明你為所有使用者設定它。你同樣可以為一組使用者設定成擁有這個檔案(g+x
),或者只為一個使用者——擁有者——設定 (u+x
)。
儘管我們會在該系列之後的部分包含從命令列建立和執行指令碼的內容,並學習通過輸入它的路徑並在結尾加上程式名的方式執行一個程式:
path/to/directory/some_program
或者,如果你當前在相同目錄,你可以使用:
./some_program
還有其他方式可以使你的程式在目錄樹的任意位置執行 (提示:查詢 $PATH
環境變數),但是當我們討論 shell 指令碼的時候你會讀到這些。
明顯地,從命令列修改和處理檔案有很多的方式,而不僅僅是處理它們的許可權。當你試圖開啟一個不存在的檔案是,大多數應用會建立一個新檔案。如果 test.txt
當前並不存在,下列命令:
nano test.txt
vim test.txt
(nano 和 vim 是流行的命令列文字編輯器)都將為你建立一個空的 test.txt
檔案來編輯。
你可以通過 “觸控” (touch
)來建立一個空的檔案,
touch test.txt
會建立一個檔案,但是不會在任何應用中開啟它。
你可以使用 cp
來拷貝一個檔案到另一個位置,或者使用一個不同的名字:
cp test.txt copy_of_test.txt
你也可以拷貝一堆檔案:
cp *.png /home/images
上面的命令拷貝當前目錄下的所有 PNG 檔案到相對你的主目錄下的 images/
目錄。在你嘗試之前 images/
目錄必須存在, 不然 cp
將顯示一個錯誤。同樣的,警惕,當你複製一個檔案到一個已經包含相同名字的檔案的目錄時,cp
會靜默地用新檔案覆蓋老的檔案。
你可以使用:
cp -i *.png /home/images
如果你想要 cp
命令在有任何危險時警告你 (-i
選項代表互動式的)。
你同樣可以複製整個目錄,但是為了做到這樣,你需要 -r
選項:
cp -rv directory_a/ directory_b
-r
選項代表遞回,意味著 cp
會向下探索目錄 directory_a
,複製所有的檔案和子目錄下內部包含的。我個人喜歡包含 -v
選項,因為它使 cp
冗長而囉嗦,意味著它會顯示你當前它正在做什麼而不是僅僅靜默的複製然後存在。
mv
命令移動東西。也就是說,它移動檔案從一個位置到另一個位置。最簡單的形式,mv
表現的更像 cp
:
mv test.txt new_test.txt
上面的命令使 new_test.txt
出現,test.txt
消失。
mv *.png /home/images
移動當前目錄下所有的 PNG 檔案到相對於你的主目錄的 images/
目錄。同樣的你必須小心你沒有意外的覆蓋已存在的檔案。使用
mv -i *.png /home/images
如果你想站在安全的角度,你可以使用與 cp
相同的方式。
除了移動與拷貝的不同外,另一個 mv
和 cp
之間的不同是當你移動目錄時:
mv directory_a/ directory_b
不需要新增遞回的標誌。這是因為你實際做的是重新命名一個目錄,與第一個例子相同,你做的是重新命名檔案。實際上,即使你從一個目錄到另一個目錄 “移動” 一個檔案,只要兩個目錄在相同的儲存裝置和分割區,你就是在重新命名檔案。
你可以做一個實驗來證明。 time
是一個工具來讓你測量一個命令花費多久來執行。找一個非常大的檔案,可以是幾百 MB 甚至 幾 GB (例如一個長視訊),像下方這樣嘗試拷貝到另一個目錄:
$ time cp hefty_file.mkv another_directory/real 0m3,868suser 0m0,016ssys 0m0,887s
下面是 time
的輸出。需要關注的是第一行, real 時間。它花費了幾乎 4 秒來拷貝 355 MB 的 hefty_file.mkv
到 another_directory/
目錄。
現在讓我們嘗試移動它:
$ time mv hefty_file.mkv another_directory/real 0m0,004suser 0m0,000ssys 0m0,003s
移動幾乎是瞬時的!這是違反直覺的,因為看起來 mv
必須複製這個檔案然後刪除原來的。這是 mv
對比 cp
命令必須做的兩件事。但是,實際上,mv
快了 1000 倍。
這是因為檔案系統結構中,它的所有目錄樹,只為了讓使用者便利而存在。在每個分割區的開始,有一個稱作分割區表的東西告訴作業系統在實際的物理磁碟上去哪找每個檔案。在磁碟上,資料沒有分為目錄甚至是檔案。作為替代的是軌道、磁區和簇。當你在相同分割區 “移動” 一個檔案時,作業系統實際做的僅僅是在分割區表中改變了那個檔案的入口,但它仍然指向磁碟上相同的簇資訊。
是的!移動是一個謊言!至少在相同分割區下是。如果你試圖移動一個檔案到一個不同的分割區或者不同的裝置, mv
仍然很快,但可以察覺到它比在相同分割區下移動檔案慢了。這是因為實際上發生了複製和清除資料。
有幾個不同的命令列 rename
工具。沒有一個像 cp
和 mv
那樣固定,並且它們工作的方式都有一點不同,相同的一點是它們都被用來改變檔名的部分。
在 Debian 和 Ubuntu 中, 預設的 rename
工具使用 正規表示式(字元組成的字串模式)來大量的改變目錄中的檔案。命令:
rename 's/\.JPEG$/.jpg/' *
將改變所有擴充套件名為 JPEG
的檔案為 jpg
。檔案 IMG001.JPEG
變成 IMG001.jpg
、 my_pic.JPEG
變成 my_pic.jpg
,等等。
另一個 rename
版本預設在 Manjaro 上可獲得,這是一個 Arch 的衍生版,更簡單,但是可能沒有那麼強大:
rename .JPEG .jpg *
這和你之前看到的上面做相同的重新命名操作。在這個版本,.JPEG
是你想改變的字元組成的字串,.jpg
是你想要改變成為的,*
表示當前目錄下的所有檔案。
基本原則是如果你所做的僅僅是重新命名一個檔案或者目錄,你最好用 mv
,這是因為 mv
在所有分發版上都是可靠一致的。
檢視 mv
和 cp
的 man 頁面了解更多。執行
man cp
或者 man mv
來閱讀這些命令自帶的所有選項,這些使他們使用起來更強大和安全。