---
# System prepended metadata

title: Shell 命令 - 檔案操作、搜尋
tags: [Linux Shell]

---

---
title: 'Shell 命令 - 檔案操作、搜尋'
disqus: kyleAlien
---

shell 命令 - 檔案操作、搜尋
===

## Overview of Content

Linux 中有許多種類的 Shell，每種 Shell 都有不同特色，這裡挑最常見的 `bash shell` 說明基礎 Bash shell 要如何使用

:::success
* 如果喜歡讀更好看一點的網頁版本，可以到我新做的網站 [**DevTech Ascendancy Hub**](https://devtechascendancy.com/)
    
    本篇文章對應的是 [**Shell 文件和目錄操作：常用命令和技巧 | 尋找檔案**](https://devtechascendancy.com/shell-file-directory-operations_query-file/)
:::

[TOC]

## Shell 操作文件、目錄


### 移動、查看自身位置：cd / pwd

* **在 Shell CLI（`Command Line Interface`） 中常用移動命令**

    | 指令 | 功能 | 補充 |
    | -------- | -------- | -------- |
    | cd | **進入指定目錄，可指定相對路進、絕對路徑** | 以`.`代表當前目錄、`..`代表上層目錄；cd \ 進入根目錄；cd ~ 進入使用者目錄；cd - 切換回上次移動的目錄 | 
    | pwd | 顯示當前目錄 |  |
    
    移動、查看自身位置的範例如下
    
    ```shell=
    ## 使用範例

    cd ~

    pwd

    cd ../../etc/

    pwd

    ## 切換到上一次所在的目錄（方便快捷用法）
    cd -
    ```
    > ![](https://i.imgur.com/3luNoyP.png)


### 文件 ＆ 目錄列表：ls

* 常用文件 ＆ 目錄列表命令

    | 指令 | 功能 | options | 補充 |
    | -------- | -------- | -------- | - |
    | ls | 查詢指定目錄下的所有文件 ＆ 目錄訊息 | 無 | **就算是空目錄也有，當前目錄`.`、父目錄`..`** |
    |  |  | -a | 顯示所有文件包括隱藏文件 |
    |  |  | -R | 分類、遞歸顯示文件 |
    |  |  | -l | 長列表 |
    |  |  | -F | 區分目錄 ＆ 文件 |
    |  |  | -i | 文件 inode 編號 |

    :::info
    * `options` 可以一次性輸入多個，並且可以合併輸入，不用分開輸入
    :::

    ```shell=
    ## 使用範例

    ls -R

    ## 指定文件
    ls ./Bookshelf/
    
    ls -l ./Bookshelf/
    
    ## 可以一次性輸入多個指令，以下指令是 -l -a -F，可以合併為 -laF
    ls -laF
    ```
    > ![](https://i.imgur.com/kLTKXmx.png)

* 使用 `l` 輸出長列表時，可以看到該文件、目錄的詳細訊息，其代表意義如下

    ```shell=
    ## ls -laF 輸出格式
    
    drwxr-xr-x  2 alien alien 4096 Feb 21 12:02 Bookshelf/
    ```
    | 原數據（左到右） | 說明 |
    | - | - |
    | drwxr-xr-x | 文件類型（`-` 文件、`d` 目錄、`c` 字符文件、`b` 塊設備）、權限（rwx） |
    | 2 | **硬連結** 總數 |
    | alien | 該文件、目錄的屬於哪個用戶 |
    | alien | 該文件、目錄的屬於哪個群組 |
    | 4096 | 該文件、目錄的大小 |
    | Feb 21 12:0296 | 上次修改時間 |
    | Bookshelf/ | 文件、目錄名 |
    
    :::success
    * 搜尋指定文件時可以使用 **正則表達式**
    
        ```shell=
        ## 1 個隨意開頭但 ello 結尾的文件
        ls -l ?ello

        ## 0 到多個 hell 開頭的文件
        ls -l hello*

        ## 中括號 [] 內的其中一個文字配對（a, e, i, o, u）
        ls -l hell[aeiou]

        ## 中括號 [] 內的其中一個文字配對 (a 到 z)
        ls -l hell[a-z]

        ## 中括號 [] 內，只要不是 a 結尾的所有可匹配文件
        ls -l hell[!a]
        ```
    :::
    
### 創建文件、資料夾：touch / mkdir

* **創建文件命令 `touch`、`mkdir`**

    | 指令 | 功能 | options | 補充 |
    | -------- | -------- | -------- | - |
    | touch | **創建文件** | 無 | 如果文件已存在，則只改變創建時間 |
    |  |  | -a | 只改變訪問時間 |
    | mkdir | **創建資料夾** | 無 | 如果已經有該資料夾則會創建失敗 |
    |  |  | -p | 批量創建子目錄 |
    
    ```shell=
    ## touch 範例
    
    touch 123.txt
    
    ## 預設顯示 上次文件修改間
    ls -l 123.txt
    
    touch -a 123.txt
    
    ## 查看文件最後被訪問的時間（access）
    ls -l --time=atime 123.txt
    ```
    > ![](https://i.imgur.com/7CZfxaK.png)


    ```shell=
    ## mkdir 範例

    mkdir myDir/my/dir
    ```
    > ![](https://i.imgur.com/D1YtxQJ.png)


* **複製文件命令 cp**

    | 指令 | 功能 | options | 補充 |
    | -------- | -------- | -------- | - |
    | cp | 複製文件 | 無 | 格式：cp <來源> <目的> |
    |  |  | -i | 判斷目的資料夾內是否有一樣的文件，如果有則會提醒 |
    |  |  | -R | 遞歸複製(通常用在複製資料夾整個內容)|
    
    :::info
    `cp` 命令中可以使用通配符
    :::

    ```shell=
    ## 將 cp_source 資料夾下的所有檔案覆到 cp_des 資料夾中
    cp -Ri ./cp_source/* ./cp_des/

    ls -laF cp_des/
    ```

    > ![](https://i.imgur.com/f68p74f.png)

### 軟/硬連結：ln

* 軟/硬連結 `ln` 命令，類似於一種**捷徑的概念**，在 Unix 系列的系統中很常會被使用到


    | 連接類型 | 說明 | 大小 | 注意 |
    | -------- | -------- | -------- | -------- |
    | 符號連結 (`Symbolic`) | 可創造目錄軟連結（**兩個完全不同的文件**） | 副本的形式的連結大小 | 有「**主從關係**」，若主被刪除，從也無法訪問到 |
    | 硬連結 | ++不可++創造目錄軟連結，**並且同步原文件更新** | 原文件大小 + 路徑的總字節數 | **原文件必須是++絕對路徑++** |

    1. 初始化檔案，並創建軟、硬連結
        ```shell=
        # 創建一個檔案
        touch file1

        # 預設 ++硬連結++ 
        ln flie1 file2

        # -s 就是 symbolic (軟連結) 
        ln -s file1 file3

        # 查看目錄屬性(並添加 i 查看 inode)
        ls -lai
        ```
        
        > ![](https://i.imgur.com/TJRHZlV.png)

        硬連結兩者同 inode 編號（同個文件），軟連結則是不同 inode 編號（不同文件），概念圖如下所示

        > 從下圖我們就可以發現如果 file1（硬連結）被刪除，那 file3（軟連結）就訪問不到真實文件了，因為 file3 是透過 file1 找到真實文件的位置；這也表示了主從關係
        ```mermaid
        graph LR
        
        f(真實文件)
        
        h1(硬連結 file1) --> i1(inode 1<br><393861>)
        h2(硬連結 file2) --> i1
        
        s2(軟連結 file3) --> i3(inode 3<br><393862>)
        
        i1 --> f
        i3 --> h1
        ```

        :::info
        * **怎樣查看 inode 編號？**
        
            如果文件 **使用硬連結**，則兩個文件會有 **相同的 inode 編號**；以範例來說，可以使用 `ls -lai` 查看文件，就會發現，硬連結數量為 2
        
            > ![](https://i.imgur.com/E1PLUEZ.png)
        :::


    2. 對 `file1` 寫入數據，查看 `file2`、`file3` 的檔案大小
        
        ```shell=
        echo "Hello12311111111111111111111111111111111111111111111111111111111111111111111111" >> file1

        ls -laF
        ```
        
        從下圖，我們看到「**硬連結**」的兩個檔案大小都有變大，「**軟連結則沒有**」

        > ![image](https://hackmd.io/_uploads/SyRk7NFJR.png)

    3. 刪除 `file1`，查看 `file2`、`file3` 的檔案，會發現軟硬連結會有不同的表現，軟連結連接不到原本數據，但硬連結則不受影響

        * **軟連結 `file3` 失效（變紅字）**
        
        * **硬連結 `file2` 數目也少 1**
        
            > ![](https://i.imgur.com/Ne44AuL.png)

            :::success
            * 硬連結可以使用是針對同一台裝置的連接，如果要連接到不同裝置，則需要使用軟連結，因為軟連結更像是「引用」的概念（多了一層抽象概念）
            :::

### 重新命名 & 移動文件：mv

* 重新命名 & 移動文件 `mv` 命令

    | 指令 | 功能 | options | 補充 |
    | -------- | -------- | -------- | - |
    | mv | **移動、重新命名文件** | 無 | 格式：mv <來源> <目的> |
    |  |  | -i | 當目標目錄有同名文件時，提醒使用者 |
    
    ```shell=
    ## 重新命名範例
    ls -laFi
    
    mv file1 file11
    
    ls -laFi
    ```
    > ![](https://i.imgur.com/TrAr7VA.png)

    :::warning
    * **重新命名後的文件 inode 不會改變**
        
        硬連結的文件會同時修改，不過 **軟連結的文件則會失效**！
    :::

### 移除文件、目錄：rm / rmdir

* 移除文件 `rm` 命令、移除目錄 `rmdir` 命令

    | 指令 | 功能 | options | 補充 |
    | -------- | -------- | -------- | - |
    | rm | **移除文件** | 無 | 格式：rm <文件> |
    |  |  | -i | 刪除前再次巡運使用者該文件是否要刪除 |
    |  |  | -r | 遞歸刪除（用來刪除某資料夾） |
    |  |  | -f | 強制刪除並不詢問 |
    | rmdir | **移除目錄** | 無 | 預設移除空目錄 |tree
    
    ```shell=
    ## rm 範例
    tree
    
    rm -i file3
    
    ls
    ```
    > ![](https://i.imgur.com/qKccqfU.png)
    
    rmdir 只能刪除空目錄
    > ![](https://i.imgur.com/HySvy28.png)

## 文件內容

這裡說明的是不使用編輯器 (vim... 之類）來查看文件的內容的命令

### 文件比較：diff

* 透過 `diff` 命令，可以比對兩個文件文本內容的差異；其格式如下

    ```shell=
    diff [options] <file1> <file2>
    ```

    範例如下
    
    ```shell=
    diff file1 file2
    ```
    
    > 可以看到差異會使用 `---` 符號隔開
    > 
    > ![](https://hackmd.io/_uploads/HJ3PPwOLn.png)

    :::info
    * 更多時會使用 `-u` Options
    :::


### 文件類型：file

* `file` 命令可以探測文件內部，並從中分析出文件是哪種類型
    
    > 可能有 UTF-8, UTF-16, ASCII... 等等格式

    ```shell=
    ## 查看硬連結
    file file2

    ## 查看資料夾
    file myDir/

    ## 創建軟連結
    ln -s file1 file3

    ## 查看軟連結
    file file3

    ## 很有用～ 查看二進制文件（同時顯示該文件運行的平台、依賴庫）
    file /bin/ls
    ```

    > ![](https://i.imgur.com/lwkedIw.png)

### 查看完整文件：cat / more / less

* 查看完整文件有多種命令，你可以挑選你想要用、適合的去使用

    | 指令 | 功能 | options | 補充 |
    | -------- | -------- | -------- | - |
    | cat | 列出文件全部內容 | 無 | - |
    | | | -n | 列出文件行號 |
    | | | -b | 列出有用的文本的行號（空白不列行號） |
    | | | -T | 替換對其符號（制表符）為 ^I|
    | more | 每到要顯示下一頁時就停止 | 無 | - |
    | less | 比起 more 更多指令可以操作 | 無 | less is more(少即是多) |

    * cat 指令使用範例
    
        ```shell=
        cat -bT ./.bashrc
        ```

        > ![](https://i.imgur.com/Z6fgASX.png)

    * more 指令使用範例
    
        ```shell=
        more ./.bashrc
        ```

        > ![](https://i.imgur.com/nNJ67EM.png)

    * less 指令使用範例
    
        ```shell=
        less ./.bashrc
        ```

        > ![](https://i.imgur.com/kbjukuV.png)

### 查看部分文件：tail / head

* 查看部分文件也有多種指令，挑選一個適合的使用即可
    
    | 指令 | 功能 | options | 補充 |
    | -------- | -------- | -------- | - |
    | tail | 查看文件尾部內容 | 無 | 預設是 10 行 |
    | | | -n <行> | 指定要看尾部幾行內容 |
    | head | 查看文件頭部內容 | 無 | 預設是 10 行 |
    | | | -n <行> | 指定要看頭部幾行內容 |

    ```shell=
    ## 使用範例
    
    head ./.bashrc

    tail ./.bashrc
    ```

    > ![](https://i.imgur.com/HMz27hc.png)


## 文件搜尋


### 文件搜尋：find / locate

| 文件搜尋命令 | 說明 |
| -------- | -------- |
| find | 搜尋指定資料夾內的資料 |     
| locate | 與 find 相同，不過它是在 **系統建立的索引中尋找檔案**（新檔案可能找不到，不過 `locate` 的搜尋效率較高） |

* `find` 命令的基礎格式如下

    ```shell=
    find [路徑] [options] [名稱]
    ```
    
    find 命令使用範例如下

    ```shell=
    # 在當前目錄下，尋找名為「二元樹」開頭的檔案

    find . -name "二元樹*"
    ```

    > ![image](https://hackmd.io/_uploads/BymfV4FkA.png)


    
## Appendix & FAQ

:::info
:::

###### tags: `Linux Shell`
