探索腳本與命令:Shell 腳本的必備相關知識 | 腳本的數學運算

探索腳本與命令:Shell 腳本的必備相關知識 | 腳本的數學運算

Overview of Content

這篇文章將帶您深入了解Shell腳本中的命令集、多命令、變量使用、命令執行、退出腳本、重定向以及管道和數學運算。

從如何創建腳本到管理腳本中的變量,再到退出腳本和利用重定向來控制輸入輸出,最後學習如何使用管道和進行數學運算

寫文章分享不易,如有引用參考請詳註出處,如有指導、意見歡迎留言(如果覺得寫得好也請給我一些支持),感謝 😀

個人程式分享時比較注重「縮排」,所以可能不適合手機的排版閱讀,建議切換至「電腦版」、「平板版」視窗看


腳本 & 命令:命令集、多命令

使用多個不同命令時,只需在每個命令之間使用 ; 隔開即可


who ; date

多命令:複合執行 &&

● 一般來說我們在使用多命令時會使用 ; 符號,稍加詳細地說這個符號會執行多個命令,而不判斷其中哪個命令是否成功

● 如果要讓命令依照順序執行,並且判斷其中是否有錯誤,可以使用 && 符號;從以下範例就可以清楚地看出其差異


# 有錯誤仍往下執行
echo "Start" ; nocmd ; echo "End"

# 有錯誤就不往下執行
echo "Start" && nocmd && echo "End"

創建 shell 腳本:命令集

腳本 & 命令

腳本就是透過多個命令組成(所以上面這個多命令也是一個簡單的腳本)

命令一次不要下達超過 255 個

● shell 腳本其實就是將指令寫入某個文件中;首先 1. 需要指定該腳本文件由哪個 Shell 分析 (#!<Shell 路徑>)、2. 寫入需要的指令


#!/bin/bash
# first bash script

date

who

指令可以使用換行分開、也可以使用 ; 分開

腳本不可運行

預設創建出來的文件會因為 umask(002),將文件權限設定為 664,也就是預設該文件是不可執行,這時 只需要透過 chmod 改變即可


chmod u+x firstShell.sh

想讓腳本在任何目錄中都可以被呼叫到

A. 將腳本目錄加入 PATH

B. 使用絕對路徑去呼叫腳本

● 腳本中如果要輸出訊息給使用者看,可以使用 echo 命令


#!/bin/bash
# first bash script

date

who

## -n 代表不換行
echo -n "Hello script~"

echo "Yo"

● 運行腳本


./firstScript.sh


腳本內使用變量

● 要在腳本中使用變量有兩種,1. 環境變數變量$<環境變量名>)、2. 腳本臨時變量(也稱為用戶變量)

變量有分大小寫

引用變量時都是使用 $ 符號,如果不使用這個符號,那變量就只是普通的字串,而不是真正的數值(透過 $ 符號才可引出數值)

環境變量

腳本中使用環境變量

● 查詢環境變量,可以使用 setprintenvenv ... 等等命令


#!/bin/bash
# use variable in script

# echo 雙引號中使用 $ 符號就可以引用變數
# 
# 如果你要使用 $ 符號,請配合跳脫符號 `\`
echo "User: $USER"
echo "Uid: $UID"
echo "Hime: $HOME"

● 運行腳本


chmod u+x 

./variable.sh

腳本臨時變量

腳本臨時變量:脫離腳本後就不復存在


#!/bin/bash 
# local variable for script

# 臨時變量
hello=1111
world=2222

echo "hello=$hello, world=$world"

● 運行腳本


chmod u+x 

./local_variable.sh


腳本內執行命令

Shell 腳本中可以從命令 A 的輸出提取訊息,並賦予變量,這種腳本內執行命令的方式也稱之為「命令替換」

命令替換符號中的命令,會由 sub shell 執行?

這不一定,是否由 sub shell 執行這取決於你使用的命令,如果是內建命令則不啟用 sub shell 執行,外部命令則啟用 sub shell 執行


# cd 就是內建命令

type cd 

可使用 type 命令來分別內建、外部命令

反引號 & 引用格式

以下有兩種方法可以把可以將命令輸出給變量

A. 反引號 `<命令>`:bash 會執行反引號內的命令(這種使用方式較為傳統)

B. 引用格式 $(<命令>):bash 會執行 $() 內的命令


#!/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 "

● 執行命令


chmod u+x catch_cmd.sh

./catch_cmd.sh

reference link


退出腳本

退出腳本對於 Shell 來說很重要,Shell 的判斷式就是判斷 Shell 退出時的退出碼來決定該命令是否執行成功!

每個指令都會執行過後都會返回 退出狀態碼(exist status),來告知該腳本執行的結果

● 狀態碼範圍為 0 ~ 255 的整數

查看退出碼:$?

● Linux 提供一個特殊符號來 $? 來保存上一個命令的退出狀態碼 (只會保留上一次的結果),其狀態碼也代表了不同意義

A. 成功:退出碼為 0


date && echo "\$? $?"

從上面實驗我們可以知道指令執行成功後返回的結果是 0,也就是 數字 0 代表命令執行成功

B. 失敗:退出碼非 0 都是失敗,並沒有特殊規則可循


# 無用命令
abc

echo "\$? $?"

● 失敗退出碼雖然沒有規則但有 慣例,我們可以按照以下慣例去判斷(但並非決定)

退出狀態碼慣例意義
0成功
1一般未知錯誤
2不合適的 shell 命令
126該命令不可執行
127找不定該命令
128無效的退出參數
128+x與 Linux 信號 x 相關的嚴重錯誤
130透過 Ctrl+C 終止命令
255正常範圍之外的退出狀態碼

以下分別執行了錯誤指令(127) & 不可執行的命令(126)

退出腳本:exit 命令

● 我們在退出腳本時可以使用 exit 命令,該指令可以指定退出碼


#!/bin/bash

var1=10
var2=20

result=$(bc<< EOF

a=$var1 * $var2
b=$var2 / $var1

a+b

EOF
)

echo "result=($result)"

exit 27

格式:exit <退出碼>

● 當給予退出碼大於 255 則會取 256 餘數

假設給 exit 555,那最終我們讀取退出碼時就會是 43 (555 % 256 的結果)


重定向:輸入/輸出

● 如果要將命令的結果輸出到另一個位置(有可能是另一個命令中、或是輸出到檔案),那就需要重定向

重定向類型符號說明
輸出重定向(覆蓋)>將命令結果輸出到另一個位置;如果輸出到文件,則會覆蓋文件內容
輸出重定向(追加)>>同上,不過不會覆蓋文件內容,而是追加文件內容
輸入重定向<將文件內容輸入到命令中
輸入重定向(條件型)<<可一直輸入內容直到指定符號,才完整輸入到命令中

輸出重定向

輸出重定向

以下範例示範輸出的重定向,使用重定向的追加符號(>>)、覆蓋符號(>


# 輸出命令 (覆蓋)
./catch_cmd.sh > redirection_output_1.txt

cat redirection_output_1.txt

# 追加輸出
./catch_cmd.sh >> redirection_output_1.txt

cat redirection_output_1.txt

輸入重定向

輸入重定向:使用 wc 指令測試輸入重定向

wc 命令是 words counts,用來判斷文件字數

wc 輸出格式「文本行數 詞數 字節數」

以下範例將 redirection_output_1.txt 檔案輸入到 wc 指令中


# 將文本內容輸入給 wc 命令

wc < redirection_output_1.txt

條件型 輸入重定向:

另外一個有趣的用法是作為「輸入的結尾條件」,當判斷到輸入的內容為指定內容,那就停止輸入,範例如下…


# 你可以一直輸入文字,直到輸入 'YoYo' 為止
# 才會將文字匯入 wc 命令運行

wc << YoYo


管道 Pipe

如果要將某個命令作為下一個命令的輸入,這時就可以使用管道技巧;管道格式如下


# 管道用法

<命令 A> | <需要 A 命令結果的命令>

管道的使用範例

● Unix 管道的使用範例


# 首先列出所有已安裝的軟體
# 將安裝軟體的結果輸出給 sort 使用(sort <上一個結果>)
# 最後將 sort 結果在輸出給 head (head <上一個結果>)
apt list --installed | sort | head

● 命令的執行順序?

兩個命令會同時執行,由系統內部將命令進行串接(就像是物件導向的 Link 鏈式設計)


腳本的數學運算

對於任何程式語言來說操作數字都是基礎能力,對於 Shell 當然也是,不過 Shell 對於數字的處理較為麻煩

Bourne shell:expr 命令

● Bourne shell 提供了一個特別的命令 expr 來處理數學表達式,其可以處理的內容如下表(提及幾個常用的)

操作符描述成立後返回不成立返回
ARG1 | ARG2ARG1 非 0 也不是 NULL 就返回 ARG1,否則返回 ARG2ARG1ARG2
ARG1 & ARG2ARG1 和 ARG2 都非 0 也不是 NULL,則返回 ARG1ARG10
ARG1 < ARG2小於10
ARG1 <= ARG2小於等於10
ARG1 = ARG2等於10
ARG1 != ARG2不等於10
ARG1 >= ARG2大於等於10
ARG1 > ARG2大於10
ARG1 + ARG2加法ARG1+ARG2-
ARG1 - ARG2減法ARG1+ARG2-
ARG1 * ARG2乘法ARG1+ARG2-
ARG1 / ARG2除法ARG1+ARG2-
ARG1 % ARG2取模ARG1%ARG2-

expr 符號的衝突

expr 符號很多會與原生 Shell 使用的符號衝突,當符號衝突時可以使用跳脫符號來避免(\


# Error `*` 符號衝突
expr 5 * 2

# 使用跳脫字元
expr 5 \* 2

● 以下範例 使用 expr 命令來運算數學


#!/bin/bash
# test expr command

var1=10
var2=20

# 記得命令替換是使用 `$()` 符號
# 內部執行 expr 命令時仍須關心是否有符號衝突的問題
result=$(expr $var1 \* $var2)

echo "$var1 * $var2 = $result"

● 執行命令


chmod u+x expr_test.sh

./expr_test.sh

Bash shell:$[ ] 符號

● Bash shell 運算中有一種更方便的方式:

使用 $[ ] 符號,使用這個符號就不用擔心符號衝突的問題


#!/bin/bash
# test $[] command

var1=10
var2=20

result=$[$var1 * $var2]

echo "$var1 * $var2 = $result"

● 執行命令


chmod u+x expr_test2.sh

./expr_test2.sh

:::warning

$[ ] 符號只能計算整數不能計算浮點數

浮點數計算:bc 命令

● 透過 bc 命令就可以計算浮點數,首先 bc 命令的基礎用法如下 (不用腳本的狀況)

輸入 quit 就可以退出計算

bc 命令還可以儲存暫時變量

:::info

bc 內建變量 scale 的設置

透過設定 scale 就可以控制計算結果輸出的小數點位數

● 在腳本中使用 bc 命令,以下有兩種方式

A. 基本使用


#!/bin/bash

var1=100.1
var2=222.3

# scale 設定最多輸出 4 個小數點
result=$(echo "scale=4; $var1 * $var2" | bc)

echo "result=($result)"

● 運行腳本


chmod u+x float_cal.sh

./float_cal.sh

B. 配合重指向:如果要較長的計算,那就可以使用「輸入重指向


#!/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)"

● 重新導向的內部局部變數是不可以使用的,否則會出錯(以上面範例來說 a1, a2 就不能拿來計算)

更多 Linux Shell 知識

探索 Debian 系統上的套件管理系統(PKMS 概念)| 套件倉庫

Linux 環境、服務:用戶、權限管理

Linux 環境、服務、管理

在這個主題中,你可以探索各種 Linux 環境、服務和管理相關的重要概念…

了解 Linux 組成:內核責任、GNU 工具、桌面環境 | 基礎版到發行版

在這裡,你將了解 Linux 系統的基本組成部分,包括內核、GNU 工具和桌面環境,並了解不同 Linux 發行版之間的差異

探索 X Window 服務與桌面環境:Linux 視窗 XWindow 服務、D-Bus 機制

這裡探討了 Linux 系統中 X Window 服務和 D-Bus 機制的工作原理,讓你深入了解桌面環境的背後運作方式

Linux 系統管理入門:安全性、用戶管理與權限設定指南

在這個指南中,你將學習如何管理 Linux 系統,包括安全性、用戶管理和權限設定,以確保系統的安全和有效運作

認識身份驗證與權限管理:UNIX UID、使用者驗證與 PAM | PAM 設定

這裡介紹了 UNIX 系統中的身份驗證機制和權限管理方式,包括 UNIX UID、使用者驗證和 PAM(Pluggable Authentication Modules)設定

Linux Shell 相關知識

Linux Shell 相關知識

這個主題涵蓋了各種與 Linux Shell 相關的知識,從基礎到進階都有…

Shell 基礎知識:包括 Shell 的基礎使用以及差異,還有變數以及計算

認識命令行:Shell 類型、命令差異 | Sub Shell 關係 | Builtin 命令

這裡介紹了命令行中不同類型的 Shell,以及各種 Shell 命令之間的區別和內建命令的用法

Shell 全局及區域變數、特殊變數及環境變數 | Shell 啟動順序 | Array 變數

學習如何在 Shell 中使用全局變數、特殊變數和環境變數,以及如何設置和管理這些變數

探索腳本與命令:Shell 腳本的必備相關知識 | 腳本的數學運算

這裡介紹了 Shell 腳本的基本知識和常用技巧,包括如何執行腳本和進行數學運算

Shell 結構化

Shell 腳本程式中的條件語句和高級特性 | Shell 結構化 & 判斷

該篇文章是介紹結構化腳本的基礎以及特殊的高級技巧,轉著於腳本中的邏輯判斷

掌握 Bash 腳本中的迴圈與循環控制技巧 | Shell 結構化 & 循環

接著是腳本中的循環與控制的技巧,它可以讓我們在 Shell 腳本中有更多的判斷與技巧

探索 Shell 函數與腳本庫 | Shell 結構化 & 函數

這裡你將會學在到結構化腳本的重要技巧「函數」,它可以讓你建立可重複利用的腳本,以節省我們之後開發的時間

Shell 掌握參數處理與用戶輸入技巧 | Shell 結構化 &輸入互動

不可互動的腳本有時候相對無趣,這篇文章有分享如何讓腳本與使用者產生交互互動,並依照使用者輸入的參數做讀取

Shell script 進階

Shell 命令輸入與輸出指南:掌握標準文件描述符與重定向 | 臨時文件

掌控 Shell、指令的輸出輸入是成為進階使用 CLI 之人必經的一課,透過這篇文章可以了解到輸出輸入、臨時文件等等資訊

探索 Linux 訊號與後台進程管理:安排定期啟動腳本 | 運行時啟動腳本

信號可以算是 Shell 腳本與 Linux 系統之間的通訊方式,透過這個文章,我們可以了解到信號與 Shell 腳本的安排時間

Linux 硬體規劃:檔案系統、分區

Linux 硬體規劃:檔案系統、分區

最後,這個主題涵蓋了 Linux 系統中硬體結構相關的重要概念…

Shell 文件和目錄操作的常用命令和技巧 | 尋找檔案

這裡介紹了 Shell 中常用的文件和目錄操作命令,包括如何尋找文件和管理文件系統

深入探索 Linux 文件系統與硬體管理 | 分區、檔案系統、邏輯卷 | inode

學習如何管理 Linux 文件系統,包括分區、文件系統和邏輯卷等相關概念,以及文件系統中的 inode 機制

理解 Unix/Linux 設備偵測、建立 | 認識與使用 udevd | SCSI 與 Linux 核心

這裡介紹了 Unix/Linux 系統中的設備偵測和管理,包括如何使用 udevd 和 SCSI 相關的 Linux 核心知識

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

發表迴響