kyle shanks
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- title: '建構腳本 - 基礎引用變量、管道、數學運算' disqus: kyleAlien --- 建構腳本 - 基礎引用變量、管道、數學運算 === ## Overview of Content 如有引用參考請詳註出處,感謝 :smile_cat: :::success * 如果喜歡讀更好看一點的網頁版本,可以到我新做的網站 [**DevTech Ascendancy Hub**](https://devtechascendancy.com/) 本篇文章對應的是 [**探索腳本與命令:Shell 腳本的必備相關知識 | 腳本的數學運算**](https://devtechascendancy.com/shell-scripting-essential-knowledge/) ::: [TOC] ## 腳本 & 命令:命令集、多命令 使用多個不同命令時,只需在每個命令之間使用 `;` 隔開即可 ```shell= who ; date ``` > ![](https://i.imgur.com/iWEuGoo.png) ### 多命令:複合執行 `&&` * 一般來說我們在使用多命令時會使用 `;` 符號,稍加詳細地說這個符號會執行多個命令,而不判斷其中哪個命令是否成功 * 如果要讓命令依照順序執行,並且判斷其中是否有錯誤,可以使用 `&&` 符號;從以下範例就可以清楚地看出其差異 ```shell= # 有錯誤仍往下執行 echo "Start" ; nocmd ; echo "End" # 有錯誤就不往下執行 echo "Start" && nocmd && echo "End" ``` > ![](https://i.imgur.com/BM54uDT.png) ### 創建 shell 腳本:命令集 :::info * **腳本 & 命令** 腳本就是透過多個命令組成(所以上面這個多命令也是一個簡單的腳本) > 命令一次不要下達超過 255 個 ::: * shell 腳本其實就是將指令寫入某個文件中;首先 ^1.^ 需要指定該腳本文件由哪個 Shell 分析 (`#!<Shell 路徑>`)、^2.^ 寫入需要的指令 > 指令可以使用換行分開、也可以使用 `;` 分開 ```shell= #!/bin/bash # first bash script date who ``` > ![](https://i.imgur.com/DFAnS94.png) :::warning * **腳本不可運行**? 預設創建出來的文件會因為 umask(002),將文件權限設定為 664,也就是預設該文件是不可執行,這時 **只需要透過 `chmod` 改變即可** ```shell= chmod u+x firstShell.sh ``` * **想讓腳本在任何目錄中都可以被呼叫到**? 1. 將腳本目錄加入 PATH 2. 使用絕對路徑去呼叫腳本 ::: * 腳本中如果要輸出訊息給使用者看,可以使用 `echo` 命令 ```shell= #!/bin/bash # first bash script date who ## -n 代表不換行 echo -n "Hello script~" echo "Yo" ``` * 運行腳本 ```shell= ./firstScript.sh ``` > ![](https://i.imgur.com/PJMLYw4.png) ## 腳本內使用變量 `$` * 要在腳本中使用變量有兩種,^1.^ **環境變數變量**(`$<環境變量名>`)、^2.^ **腳本臨時變量**(也稱為用戶變量) > 變量有分大小寫 * **引用變量時都是使用 `$` 符號**,如果不使用這個符號,那變量就只是普通的字串,而不是真正的數值(透過 `$` 符號才可引出數值) ### 環境變量 * **腳本中使用環境變量** :::info * 查詢環境變量,可以使用 `set`、`printenv`、`env` ... 等等命令 ::: ```shell= #!/bin/bash # use variable in script # echo 雙引號中使用 $ 符號就可以引用變數 # # 如果你要使用 $ 符號,請配合跳脫符號 `\` echo "User: $USER" echo "Uid: $UID" echo "Hime: $HOME" ``` * 運行腳本 ```shell= chmod u+x ./variable.sh ``` > ![](https://i.imgur.com/Ioyuuwo.png) ### 腳本臨時變量 * **腳本臨時變量**:脫離腳本後就不復存在 ```shell= #!/bin/bash # local variable for script # 臨時變量 hello=1111 world=2222 echo "hello=$hello, world=$world" ``` * 運行腳本 ```shell= chmod u+x ./local_variable.sh ``` > ![](https://i.imgur.com/T2VwslF.png) ## 腳本內執行命令 Shell 腳本中可以從命令 A 的輸出提取訊息,並賦予變量,這種腳本內執行命令的方式也稱之為「命令替換」 :::danger * **命令替換符號中的命令,會由 sub shell 執行?** 這不一定,是否由 **sub shell 執行這取決於你使用的命令**,如果是內建命令則不啟用 sub shell 執行,外部命令則啟用 sub shell 執行 > 可使用 `type` 命令來分別內建、外部命令 ```shell= # cd 就是內建命令 type cd ``` > ![](https://i.imgur.com/IKMB2Hw.png) ::: ### 反引號 & 引用格式 * **以下有兩種方法可以把可以將命令輸出給變量** 1. **反引號** \`<命令>\`:**bash 會執行反引號內的命令**(這種使用方式較為傳統) 2. **引用格式** $(<命令>):**bash 會執行 $() 內的命令** ```shell= #!/bin/bash # catch the command output # 反引號 catch_1=`date` echo "catch the output by \` \`: $catch_1 " # 引用格式 catch_2=$(date) echo "catch the output by \$( ): $catch_2 " ``` * 執行命令 ```shell= chmod u+x catch_cmd.sh ./catch_cmd.sh ``` > ![reference link](https://i.imgur.com/omeVtAx.png) ## 退出腳本 退出腳本對於 Shell 來說很重要,Shell 的判斷式就是判斷 Shell 退出時的退出碼來決定該命令是否執行成功! > **每個指令都會執行過後都會返回 ++退出狀態碼(exist status)++**,來告知該腳本執行的結果 :::info * 狀態碼範圍為 0 ~ 255 的整數 ::: ### 查看退出碼:`$?` * Linux 提供一個特殊符號來 **`$?` 來保存上一個命令的退出狀態碼** (只會保留上一次的結果),其狀態碼也代表了不同意義 1. 成功:退出碼為 0 ```shell= date && echo "\$? $?" ``` > ![](https://i.imgur.com/gchRC87.png) 從上面實驗我們可以知道指令執行成功後返回的結果是 0,也就是 **數字 0 代表命令執行成功** 2. 失敗:退出碼非 0 都是失敗,並沒有特殊規則可循 ```shell= # 無用命令 abc echo "\$? $?" ``` > ![](https://i.imgur.com/Ate7fzy.png) :::success * 失敗退出碼雖然沒有規則但有 **慣例**,我們可以按照以下慣例去判斷(但並非決定) | 退出狀態碼 | 慣例意義 | | - | - | | 0 | 成功 | | 1 | 一般未知錯誤 | | 2 | 不合適的 shell 命令 | | 126 | 該命令不可執行 | | 127 | 找不定該命令 | | 128 | 無效的退出參數 | | 128+x | 與 Linux 信號 x 相關的嚴重錯誤 | | 130 | 透過 Ctrl+C 終止命令 | | 255 | 正常範圍之外的退出狀態碼 | > 以下分別執行了錯誤指令(127) & 不可執行的命令(126) > > ![](https://i.imgur.com/XrTXPzX.png) ::: ### 退出腳本:exit 命令 * 我們在退出腳本時可以使用 `exit` 命令,該指令可以指定退出碼 > 格式:exit <退出碼> ```shell= #!/bin/bash var1=10 var2=20 result=$(bc<< EOF a=$var1 * $var2 b=$var2 / $var1 a+b EOF ) echo "result=($result)" exit 27 ``` > ![](https://i.imgur.com/yepyhrL.png) :::warning * 當給予退出碼大於 255 則會取 256 餘數 > 假設給 exit 555,那最終我們讀取退出碼時就會是 43 (555 % 256 的結果) ::: ## 重定向:輸入/輸出 * 如果要將命令的結果輸出到另一個位置(有可能是另一個命令中、或是輸出到檔案),那就需要重定向 | 重定向類型 | 符號 | 說明 | | - | - | - | | 輸出重定向(覆蓋)| > | 將命令結果輸出到另一個位置;如果輸出到文件,則會覆蓋文件內容 | | 輸出重定向(追加) | >> | 同上,不過不會覆蓋文件內容,而是追加文件內容 | | 輸入重定向 | < | 將文件內容輸入到命令中 | | 輸入重定向(條件型) | << | 可一直輸入內容直到指定符號,才完整輸入到命令中 | ### 輸出重定向 * **輸出重定向**: 以下範例示範輸出的重定向,使用重定向的追加符號(`>>`)、覆蓋符號(`>`) ```shell= # 輸出命令 (覆蓋) ./catch_cmd.sh > redirection_output_1.txt cat redirection_output_1.txt # 追加輸出 ./catch_cmd.sh >> redirection_output_1.txt cat redirection_output_1.txt ``` > ![](https://i.imgur.com/aI8s3ZV.png) ### 輸入重定向 * **輸入重定向**:使用 `wc` 指令測試輸入重定向 > `wc` 命令是 words counts,用來判斷文件字數 > > wc 輸出格式「文本行數 詞數 字節數」 以下範例將 `redirection_output_1.txt` 檔案輸入到 `wc` 指令中 ```shell= # 將文本內容輸入給 wc 命令 wc < redirection_output_1.txt ``` > ![](https://i.imgur.com/MsNY1SB.png) * **條件型** 輸入重定向: 另外一個有趣的用法是作為「**輸入的結尾條件**」,當判斷到輸入的內容為指定內容,那就停止輸入,範例如下… ```c= # 你可以一直輸入文字,直到輸入 'YoYo' 為止 # 才會將文字匯入 wc 命令運行 wc << YoYo ``` > ![](https://i.imgur.com/85c1Dnj.png) ## 管道 Pipe 如果要將某個命令作為下一個命令的輸入,這時就可以使用管道技巧;管道格式如下 ```shell= # 管道用法 <命令 A> | <需要 A 命令結果的命令> ``` ### 管道的使用範例 * Unix 管道的使用範例 ```shell= # 首先列出所有已安裝的軟體 # 將安裝軟體的結果輸出給 sort 使用(sort <上一個結果>) # 最後將 sort 結果在輸出給 head (head <上一個結果>) apt list --installed | sort | head ``` > ![](https://i.imgur.com/JzA9TzJ.png) :::info * 命令的執行順序? **兩個命令會同時執行**,由系統內部將命令進行串接(就像是物件導向的 Link 鏈式設計) ::: ## 數學運算 對於任何程式語言來說操作數字都是基礎能力,對於 Shell 當然也是,不過 **Shell 對於數字的處理較為麻煩** ### Bourne shell - `expr` 命令 * Bourne shell 提供了一個特別的命令 `expr` 來處理數學表達式,其可以處理的內容如下表(提及幾個常用的) | 操作符 | 描述 | 成立後返回 | 不成立返回 | | - | - | - | - | | `ARG1 \| ARG2` | ARG1 非 0 也不是 NULL 就返回 ARG1,否則返回 ARG2 | ARG1 | ARG2 | | `ARG1 & ARG2` | ARG1 和 ARG2 都非 0 也不是 NULL,則返回 ARG1 | ARG1 | 0 | | `ARG1 < ARG2` | 小於 | 1 | 0 | | `ARG1 <= ARG2` | 小於等於 | 1 | 0 | | `ARG1 = ARG2` | 等於 | 1 | 0 | | `ARG1 != ARG2` | 不等於 | 1 | 0 | | `ARG1 >= ARG2` | 大於等於 | 1 | 0 | | `ARG1 > ARG2` | 大於 | 1 | 0 | | `ARG1 + ARG2` | 加法 | ARG1+ARG2 | - | | `ARG1 - ARG2` | 減法 | ARG1+ARG2 | - | | `ARG1 * ARG2` | 乘法 | ARG1+ARG2 | - | | `ARG1 / ARG2` | 除法 | ARG1+ARG2 | - | | `ARG1 % ARG2` | 取模 | ARG1%ARG2 | - | :::danger * **expr 符號的衝突** expr 符號很多會與原生 Shell 使用的符號衝突,當符號衝突時可以使用跳脫符號來避免(`\`) ```shell= # Error `*` 符號衝突 expr 5 * 2 # 使用跳脫字元 expr 5 \* 2 ``` > ![](https://i.imgur.com/kJiYwZD.png) ::: * 以下範例 **使用 `expr` 命令來運算數學** ```shell= #!/bin/bash # test expr command var1=10 var2=20 # 記得命令替換是使用 `$()` 符號 # 內部執行 expr 命令時仍須關心是否有符號衝突的問題 result=$(expr $var1 \* $var2) echo "$var1 * $var2 = $result" ``` * 執行命令 ```shell= chmod u+x expr_test.sh ./expr_test.sh ``` > ![](https://i.imgur.com/b7xQjxJ.png) ### Bash shell - `$[ ]` 符號 * Bash shell 運算中有一種更方便的方式: 使用 `$[ ]` 符號,使用這個符號就不用擔心符號衝突的問題 ```shell= #!/bin/bash # test $[] command var1=10 var2=20 result=$[$var1 * $var2] echo "$var1 * $var2 = $result" ``` * 執行命令 ```shell= chmod u+x expr_test2.sh ./expr_test2.sh ``` > ![](https://i.imgur.com/zis7O9l.png) :::warning * **`$[ ]` 符號只能計算整數**,**不能計算浮點數** > ![](https://i.imgur.com/KtXGS26.png) ::: ### 浮點數計算:bc 命令 * 透過 `bc` 命令就可以計算浮點數,首先 `bc` 命令的基礎用法如下 (不用腳本的狀況) > 輸入 `quit` 就可以退出計算 > > ![](https://i.imgur.com/dpE0025.png) `bc` 命令還可以儲存暫時變量 > ![](https://i.imgur.com/9pIW7Ri.png) :::info * **bc 內建變量 `scale` 的設置** 透過設定 scale 就可以控制計算結果輸出的小數點位數 ::: * 在腳本中使用 `bc` 命令,以下有兩種方式 1. **基本使用** ```shell= #!/bin/bash var1=100.1 var2=222.3 # scale 設定最多輸出 4 個小數點 result=$(echo "scale=4; $var1 * $var2" | bc) echo "result=($result)" ``` * 運行腳本 ```shell= chmod u+x float_cal.sh ./float_cal.sh ``` > ![](https://i.imgur.com/DcI4xvK.png) 2. **配合重指向**:如果要較長的計算,那就可以使用「**輸入重指向**」 ```shell= #!/bin/bash var1=1.12 var2=3.1415926 var3=102 result=$( bc << END scale=5 a1=($var1 * $var2) a2=(($var2 + $var1) * $var3) a1 + b2 END ) echo "final result=($result)" ``` :::danger * 重新導向的內部局部變數是不可以使用的,否則會出錯(以上面範例來說 `a1`, `a2` 就不能拿來計算) ::: > ![](https://i.imgur.com/Zpvu8sG.png) ## Appendix & FAQ :::info ::: ###### tags: `Linux Shell`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully