顯示具有 Linux Shell Script 標籤的文章。 顯示所有文章
顯示具有 Linux Shell Script 標籤的文章。 顯示所有文章

2025年8月6日 星期三

Linux kernel minor upgrade

 今天嘗試把 kernel v4.19.98 作微升級,要升級到 v4.19.325,因為我們原本的 kernel 並不是原生最乾淨的 Linux kernel v4.19.98(是拿MTK平台的 SDK),先講我打上了這兩個版本中間的 patch,但最終編譯,卻有一堆error,解不完

 但我認為,作這件事情,中間的過程,是值得作個記錄的,因此寫了這篇文章,來記錄中間所做的步驟。

1. 下載 Linux 的 branch,使用指令如下:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

2. 每個版本都有打上tag,因此我們可以先 checkout 到 v4.19.325
git checkout v4.19.325

3. git log 確認一下 v4.19.325 與 v4.19.98 分別的 commit hash 號碼是多少










4. 使用指令,把 98 ~ 325 這中間的 commit 都作成 patch 檔,指令如下:
git format-patch d183c8e2647a7d45202c14a33631f6c09020f8ac..a67e7cdde7cc7984ae24c3c81a70dc1aa34424b1 -o patch/

5. 可以看到,目前目錄底下,會產出資料夾 patch/ ,裡面有 19xxx個patch 檔,依序都做好了編號

6. 接著我們準備要來打 patch,先說明一下,我目前的目錄環境是這樣,
apps/src/kernel/linux/4.19/,我目前專案的 repository 是在 apps底下,也就是我可以在 apps底下執行 git log,可以看到以往的 commit 資訊,而目前是要把 linux patch 打到   apps/src/kernel/linux/4.19/ 底下

7. 因為第6.的關係,我們把 patch/ 移動到 apps底下,我們打patch 的指令會如下:
cd apps/
git am --directory=src/kernel/linux/v4.19 patch/* -3  

(加上 -3(或 --3way)後,如果直接套用失敗,Git 會嘗試用三方合併的方式來解決衝突,這樣有時候可以自動解決一些簡單的衝突)

8. 打patch 的途中,會遇到許多的 conflict,你會需要開啟檔案,去解衝突,但我發現 19xxx筆patch,要解的 conflict 實在太多了,後來遇到 conflict 直接使用以下command,意思是直接幫我把衝突的舊檔案的部分刪除,把新的patch 新增的內容,改到檔案裡面: 
git checkout --theirs $file (file帶入中途的檔案路徑 與 名稱)

9. 途中會遇到一些,甚麼都沒改的 patch,會需要手動執行 git am --skip 來繼續,另外解完 conflict 的檔案,要手動執行 git am --continue 來讓 git am 繼續跑

10. 另外有遇到一個,git am 打patch,我發現有一個限制,就是打到 9999個 patch的時候,你再輸入 git am --continue 會沒辦法繼續,如下圖,這時候你必須要先 git push,把先前打的patch 都git push,然後再繼續從第 10000筆繼續打,我的作法是




   







   a. 在作第4部的時候,也順便把檔案列表資訊,輸出到一個檔案:
git format-patch d183c8e2647a7d45202c14a33631f6c09020f8ac..a67e7cdde7cc7984ae24c3c81a70dc1aa34424b1 -o patch/ > patch_list.txt
   b. 想辦法使用 note 或是 Notepad++ 把這些列表改成
rm 0001-xxxx
rm 0002-xxxx
..
rm 9999-xxxx
   c. 切換到 patch/ 資料夾,把 0001~9999 的patch 檔案都刪除
   d. 在接著使用git am 的命令繼續打剩餘的 patch:
git am --directory=src/kernel/linux/v4.19 patch/* -3  


結論: 
   1. 我在這次的過程中,寫了以下兩隻script,當發生conflict,就使用git checkout --theirs $file 去解conflict,因此可以一直遞迴去處理patch,但遇到 git am --continue 無法繼續的空內容,目前就是手動去下 git am --skip
   2. 其實比較好的做法,應該要是以下步驟
        a. 先 git checkout 到 linux pure v4.19.98
        b. 把vendor最一開始給的 kernel 覆蓋到
 linux pure v4.19.98
        c. git diff 看一下改了那些檔案
        d. 直接把 
linux pure v4.19.98,checkout 到 v4.19.325,然後試著把 前一步驟,git diff 的改回去,但如果真的差異太大,就是一個很大的工程了....

以下分享我的兩個 shell script: (主要就是執行 ./for_loop.sh)

主程式:  for_loop.sh

#!/bin/sh
for i in {1..20000}
do
    ./fail_process.sh
    if [ $? -eq 2 ]; then
        echo "fail_process.sh failed, stopping loop."
        break
    fi
done

副程式:  fail_process.sh

#!/bin/sh

# Get the list of files marked as "both modified" from gg (git status)
files0=$(git status | grep "both modified:" | awk -F: '{print $2}' | xargs)

# For each file, run git add
for file in $files0; do
    echo "Processing $file ..."
    git checkout --theirs $file
    git add $file
done


# Get the list of files marked as "deleted by them:" from gg (git status)
files1=$(git status | grep "deleted by them:" | awk -F: '{print $2}' | xargs)

# For each file, run git add
for file in $files1; do
    echo "Processing $file ..."
    git add $file
done

# Get the list of files marked as "deleted by us:" from gg (git status)
files2=$(git status | grep "deleted by us:" | awk -F: '{print $2}' | xargs)

# For each file, run git add
for file in $files2; do
    echo "Processing $file ..."
    git add $file
done


# Get the list of files marked as "both added" from gg (git status)
files3=$(git status | grep "both added:" | awk -F: '{print $2}' | xargs)

# For each file, run git add
for file in $files3; do
    echo "Processing $file ..."
    git checkout --theirs $file
    git add $file
done

if [ -z "$files0" ] && [ -z "$files1" ] && [ -z "$files2" ] && [ -z "$files3" ]; then
        exit 2
fi

git status
git am --continue



2025年1月7日 星期二

Linux Tool, taskset 可以用來限制程式,只去使用特定 CPU

 Linux 當中有個Tool,叫做 taskset,可以限制某個Daemon只跑在規定的CPU編號之下,這邊會先簡單介紹 taskset使用方式,不免俗的,最後會附上一個實際操作

首先簡單寫一個 while迴圈,打印test的字樣,但不顯示在螢幕上,這支來當我們的Daemon,並且使用以下command,讓他在背景執行
=> sh loop_test.sh &
======= loop_test.sh 小程式 =========
#!/bin/sh
while [ 1 ]
do
   echo "test" > /dev/null
done



======= 使用方式 =======

首先我們可以用以下的指令,來得知目前設備的 CPU核心數目
=> cat /proc/cpuinfo

查詢目前的 Daemon,所配置的 CPU編號,這有兩種查詢方式
1. 直接列出,此Daemon使用的CPU編號,這邊Daemon的 PID=5622 (ps -aux | grep loop_test.sh)
=>
root:~# taskset -cp 5622
pid 5622's current affinity list: 0,1

2. 以mask方式列出,此Daemon使用的CPU編號,這邊Daemon的 PID=5622
=>
root:~# taskset -p 5622
pid 5622's current affinity mask: 3

這邊的3,為Hex,需要把他換成二進制來解讀,所以為 0x11,表示CPU0,CPU1目前會讓此Daemon使用(如果CPU為8 core,得到的數值為FF(hex),則表示 CPU0~7都會分配)


======= 使用方式 & 實驗 =======
設置目前的 Daemon,只分配CPU1 來做

=>
root:~# taskset -cp 1 5622
pid 5622's current affinity list: 0,1
pid 5622's new affinity list: 1

"top -d 1" 觀察一下cpu 與 process 狀態

=> 可以看到 CPU1 的 idle為0%,loop_test.sh 把整個CPU1用盡了,而CPU0是完全閒置的











這時候,我們再使用指令把 loop_test.sh 平均分配給 CPU0 & CPU1
=>
root@auto2735evb-ivt-vp2:~# taskset -cp 0,1 5622
pid 5622's current affinity list: 1
pid 5622's new affinity list: 0,1

"top -d 1" 觀察一下cpu 與 process 狀態
=> 可以看到 CPU0與CPU1,都有分配給 loop_test.sh使用



2021年1月10日 星期日

Shell script 範例

 1. 判斷此script若是沒有帶入參數,則變數foo的值為"jacky",若有帶入一個參數值為"danny",則指定foo的值為此參數值

==========================================================

#!/bin/sh
[ -z "$1" ] && FOO="jacky" || FOO="$1"  #$1 assign "danny"

echo "$FOO"

===========================================================






2. 判斷檔案"123.txt"是否存在的範例

==========================================================

#!/bin/sh
if [ -f  "123.txt" ]; then
echo "File exist ..."
else
echo "File not exist!"
fi

===========================================================


3. 判斷檔案副檔名是否為".bin" 以及 判斷檔案大小為 "131072" Byte

==========================================================

#!/bin/sh
FILEPATH="/data/aaa.bin"
EXT="${FILEPATH##*.}"  #取得副檔名
echo "test ext=$EXT"
FSIZE=`ls -l $FILEPATH | awk '{ print $5 }'`    #取得file size

###### check file extention ######
if [ "$EXT" == "bin" ]; then
    echo "file format is ok..."
else
    echo "file format error!"
fi

###### check file size ########
echo "test FSIZE=$FSIZE"
if [ "$FSIZE" == "131072" ]; then
    echo "file size is ok..."
else
    echo "file size error!"
fi

==========================================================


4. 在While loop 當中,每隔5秒,交錯做兩件事 (A事情 / B事情)

==============================================

#!/bin/sh

count=0

while [ 1 ]
do
        count=$(($count+1))

        if [ $(( count%2 )) == 0 ]; then
                        echo "Do A things !!!"
        else
                        echo "Do B things !!!"
        fi
        echo $count
        sleep 5
done

===================================================

持續增加中........


2020年11月17日 星期二

shell script 帶參數, 印出usage使用方式的程式框架

 撰寫Script常常會帶入參數,又需要當使用者沒有帶入參數時,要印出使用方法.

下面的程式框架是要求使用者帶入兩個參數,如果使用錯誤,則印出usage()告知使用者.

此檔案 test.sh實際做法如下:

#!/bin/sh

function usage()

{

    echo "test.sh.sh [arg1] [arg2]"

    echo "ex: test.sh 1 2"

}

if [ "$#" -lt "2" ]; then

    usage

    exit 0

fi

#If arg1 and arg2 exist, then do following thing...   


2020年10月27日 星期二

shell script if 判斷多個條件

 if判斷多個條件的寫法如下: (sh)

=================

#!/bin/sh
A=10
B=15

if [ $A = "10" ] && [ $B = "15" ]; then
    echo "A=10 and B=15"
fi

if [ $A = "10" ] || [ $B < $A ]; then
    echo "A=10 or B<A"
fi



2020年9月22日 星期二

Shell script使用for來parser以空白做間格的字串

 Shell script使用forparser以空白做間格的字串 (Bash)

 #!/bin/bash

package="111 222 333 555 666"

for p in ${package[@]}; do

    echo $p

done

 

實際執行結果,如下圖



2020年9月21日 星期一

cp: will not overwrite just-created

 今天 跑Script的途中,遇到一個問題 cp: will not overwrite just-created,而導致script停了下來

其發生主要的原因是,當我們 cp 或是 mv 兩個不同地方,卻是同樣的檔案名稱到同一個目錄底下

系統為了防止第二個文件去覆蓋第一個文件,所以報錯誤

 

今天遇到了,才知道會有這樣子的錯誤訊息,以上~


實際範例說明:  

有a, b, c三個資料夾,a與b資料夾內都有一個叫做file的檔案,接著我們故意一行指令同時複製a底下的file,與b底下的file到c資料夾,如下圖所示,就會出現此錯誤訊息!





2019年9月3日 星期二

[shell script] 2進制,10進制,16進制的轉換方法

1. 搭配ibase, obase, bc 能夠達到進制轉換的目的
2. ibase => input base為幾進制,obase => output base為幾進制
3. 注意須先寫obase,再去寫ibase

上面幾點注意事項了解了之後,來看實際範例:

example: 16進制"35"轉10進制
echo "obase=10; ibase=16; 35" | bc
=> 53

example: 16進制"C0"轉10進制
echo "obase=10; ibase=16; C0" | bc
=>192

實際應用可以這樣
value=`echo "obase=10; ibase=16; C0" | bc`
echo $value
=>192


或是可以這樣
tmp=C0
value=`echo "obase=10; ibase=16; $tmp" | bc`
echo $value
=>192

============= 如果沒有 bc 可以使用, 則用下面方式(only 16轉10) ============
echo $((0x35))
=> 53

使用變數的用法
hexVal=35
echo $((0x${hexVal}))
=> 53

2019年4月2日 星期二

使用Linux dd command 清除硬碟的 partition table

假設有顆硬碟為 /dev/sda

使用下面指令可以清空硬碟的 partition table

dd if=/dev/zero of=/dev/sda bs=512 count=1

因為硬碟的partition table 通常放在 最前面的 512Byte 的地方

如果想把硬碟回到最初始的狀態,可以這樣作~

2019年3月26日 星期二

使用grep的-v參數,來排除某些字串的方法

目前我們的Code Server為SVN,整個Project裡面有包含整包Linux Source Code,假設這包Code被編譯過,當我們使用svn status的時候,就會多出很多"?"的選項,如下圖:(問號在SVN裡面就是新產生的檔案)













假設我們現在改了一些檔案,又想透過SVN從Project裡面知道改了哪些,可以使用grep -v "?" 就可以把"?"的檔案排除掉,就可以看到"M"的檔案,因此我們可以這樣下:

svn status | grep -v "?"

2019年3月7日 星期四

[shell] shell script的字串處理,取某幾個字元,cut 的用法

shell script當中要取字串有個最簡單的方法,如下:
假設現在有個字串"Hi we are the world!"







上面程式第一個 echo 表示,我要從第三個字元之後開始取,取到最終
上面程式第二個 echo 表示,我要從第三個字元之後開始取,共取8個字元
執行結果會如下圖:





cut
我們也可以用cut指令來取得特定位置字元
一樣用上面的範例 有個字串為 "Hi we are the world!"
假設我要取第4個字元到第9個
我們可以這樣下:



另外cut也可以用來作分割處理,例如我想用"空格"來分割,並取第3個字串






2019年1月25日 星期五

[shell script] 迴圈中,動態變數名稱的使用方法與限制

在Linux4.14.12的環境下

今天我要寫一個Script可以去判斷3顆硬碟的sata速度是否為6.0 Gbps,目前已知Linux底下讀sata硬碟速度的device位置分別為(每台電腦的/sys/class/ata_link/link7/sata_spd  紅字部分會不相同):
        HDD1  ===> /sys/class/ata_link/link7/sata_spd
        HDD2  ===> /sys/class/ata_link/link8/sata_spd
        HDD3  ===> /sys/class/ata_link/link9/sata_spd



完整script寫法,動態變數的方法,如下方粗體字部分:
=================== check_sata_speed.sh ==================
#!/bin/sh
HDD1="7"
HDD2="8"
HDD3="9"

BAY_3=3
i=1

        HDDSPD1=`cat /sys/class/ata_link/link$HDD1/sata_spd | awk -F' ' '{print $1}'`
        HDDSPD2=`cat /sys/class/ata_link/link$HDD2/sata_spd | awk -F' ' '{print $1}'`
        HDDSPD3=`cat /sys/class/ata_link/link$HDD3/sata_spd | awk -F' ' '{print $1}'`

        while [ $i -le $BAY_3 ]
        do
                eval "HDD_SPD=\$HDDSPD$i"
                if [ "6.0" == "$HDD_SPD" ]; then
                        count=$(($count+1))
                else
                        echo "HDD$i Fail"
                fi
                i=$(($i+1))
        done

        if [ $count == $BAY_3 ]; then
                echo "OK"
        fi
=========================================================
如果三顆硬碟都為6.0 Gbps 則最後印出 OK
若是有低於6.0的速度,則會印出Fail


***注意動態變數的使用限制
上面的HDDSPD1~HDDSPD3變數,若是你宣告為 HDD1_SPD ~ HDD3_SPD,則在迴圈內使用(eval "HDD_SPD=\$HDD$i_SPD")動態變數時,是不會成功的,只有把動態變數的數字放在變數名稱最後,才會work

已上~



2019年1月17日 星期四

[shell script] shell script 的無窮迴圈寫法

下面的範例是使用一個while無窮迴圈,每隔1秒,會印出 count值,執行後請按[ctrl+c]來結束程式

==========================================================
#!/bin/sh
count="1"
while [ 1 ]
do
echo $count
count=$(($count+1))
sleep 1
done
=========================================================



另外下面的範例也是使用一個while無窮迴圈搭配判斷式,在跑到第7次時結束並離開程式

==========================================================
#!/bin/sh
count="1"
while [ 1 ]
do
echo "do loop"
if [ $count -eq "7" ]; then
 exit
fi
count=$(($count+1))
done
=============================================================

2018年5月24日 星期四

[shell script] shell script 的Debug方法

假設有一支Shell script 名為TEST.sh,我們可以使用下面的指令來作Debug

sh -x TEST.sh

執行下去之後,會印出整個shell執行的內容與過程,透過這些內容,你可以發現是否有哪些變數寫錯了~

2018年5月16日 星期三

[shell script] 將script 指令指派給變數的方法,變數可取得回傳值

兩種方法可以達到此目的

1. 變數=`command`
ex:
     nowDate=`date  +%s`


2. 變數=$(command)
ex:
    nowDate2=$(date +%s)



寫一個測試shell script
========== command.sh =============
#!/bin/sh
nowDate=`date +%s`
nowDate2=$(date +%s)

echo "nowDate=$nowDate"
echo "nowDate2=$nowDate2"
=================================

實際測試結果,如下圖:



2018年4月10日 星期二

【shell script】Script中,單引號與雙引號,對於變數的差別


變數(例如$Num) 當在'  '裡面時 就只被當作一個字串而不會自動轉成變數的值
ex:
   Num=6
   1. echo '${Num}'     ===>   ${Num}
   2. echo "${Num}"    ===>   6


另外當script有error時,可以透過 -x 參數來作Debug
sh -x /test.sh  <====可以做Debug用途

2018年2月1日 星期四

【shell script】shell script的 "字串比較","數字相加","數字判斷","數字累加","取字串長度",的用法

shell script 的字串比較:
                  yn="GG"
                  if [ "${yn}" == "GG" ]; then
                         echo "is the same !!"
                  fi

shell script 的字串比較方法2 (如果上面判斷行不通):
                  yn="GG"
                  um="GG"
                  if [ ${yn} == ${um} ]; then
                         echo "is the same !!"
                  fi


shell script 的數字相加:
                  a="10"
                  b="20"
                  c=`expr $a + $b`

shell script 的數字判斷:
                  declare -i num="60"
                  if [ $num -gt 50 ]; then
                          echo "correct !!!"
                  fi

shell script 的數字累加:
                  count="1"
                  count=$(($count+1))
                  echo "$count"

shell script 的取字串長度:
                 STR="12345678"
                 LEN=`echo ${#STR}`
                 echo "STR length is $LEN" => 印出 "STR length is 8"

2017年11月24日 星期五

【shell script】如何判斷變數為空

下面兩種寫法都可以用來判斷變數是否為空值

================ function 1 ==============
#!/bin/sh

if [ ! -n "​​$foo" ]; then
  echo "IS NULL"
else
  echo "NOT NULL"
fi
======================================


================ function 2 ==============
#!/bin/sh

if [ ! "$​​foo" ]; then
  echo "IS NULL"
else
  echo "NOT NULL"
fi
======================================

【shell script】印出檔案中的每一行內容

下面要實作一個範例,這個Script可以取得檔案每一行的內容,並且搭配其他指令來處理


目的:以檔案的內容,來批次的尋找檔案是否存在
OS:Ubuntu

假設5566.txt 內容:
usr/lib/liba.so
usr/lib/libc.so
usr/lib/libd.so
usr/lib/libe.so

此Script的動作有幾個步驟:
1. 一行一行讀取5566.txt的內容,把每行的內容放到$line當中
2. 搭配awk來處理$line,只取得整行路徑最後的檔案名
3. 會在當下目路去尋找,是否有liba.so、libc.so、libd.so、libe.so這四個library,有的話則會印出來


================= parseTXT.sh ===============
#!/bin/sh
filename="5566.txt"
exec < $filename

while read line
do
   #echo $line
   lib=$(echo $line | awk -F'/' '{print $NF}')    #get last one
   #awk '{print $(NF-1)}'    #get last two
   result=$(find . -name $lib)
   #如果尋找的結果非空,則印出來
   if [ -n "$result" ]; then
        echo $result
   fi
   count=$(($count+1))
done
echo "count=$count"
================================================

2017年1月19日 星期四

Shell Script簡易教學

一、概論

在許多的情況之下,我們都需要固定一組可以重覆或判斷資訊的指令,
而把這些指令存被在文字檔中,再交由Shell執行,就是Script。
一般會將Shell Script的副檔名命名為.sh,雖然副檔名在Linux中並非必要,
但是有副檔名可以讓我們更容易管理這些檔案。

假設有一個名為test.sh 的 Shell Script,首先用文字編輯器來撰寫內容如下:
#!/bin/sh
echo "Hello World"

第一行是必需的,它是用來定義你要使用的 shell。Linux中有許多的Shell可以使用,
如:ksh、bash、sh,但是彼此之間語法有所差異,所以我們首先需要定義使用哪一個Shell。
而第二行的 echo 代表列出一個字串,預設會把後面的字串「Hello World」顯示在螢幕上。
將test.sh存檔後,可以用下列其中一種方式執行它:
1、直接輸入 sh test.sh
2、改變test.sh的權限,加上可以執行的權限,
   chmod a+x test.sh
   接著直接執行它:
   ./test.sh

在Shell Script中,「#」表示註解,在#後面將視為註解並且被程式忽略。
例如:
#pwd
ls -l
Shell只會執行ls -l,而不會執行ls -l

而「;」 則代表指令的分隔,例如:
pwd;ls -l

pwd
ls -l
都是一樣執行pwd及ls -l。

二、變數的使用

在Shell Script中,所有的變數都視為字串,因此不需要在定義變數類型。
在Shell中定義和使用變數時並不一樣。
例如,定義一個變數id並且設定值為2013001,接著還要將印出變數的值:
id=2013001 -> 定義變數時前面不加「$」符號
echo $id   -> 使用變數時前面要加「$」符號
注意,在等號的二邊不可以有空白,否則將出現錯誤。

再介紹一個範例:
dir=/home/danny
ls $dir

這裡我們定義了變數dir的值為/home/danny,接著用ls指令,
此時指令會變為ls /home/danny,所以就把目錄中所有檔案都列出來。


我們再來看一個例子,說明如何使用變數來定義變數:
tmppath=/tmp

tmpfile=$tmppath/abc.txt
echo $tmpfile
結果會印出   =====>  /tmp/abc.txt

我們也可以把指令的輸出傳回給變數,指令前後加上關鍵字「`」,
它是位於鍵盤左上角「數字鍵1」左邊的按鍵:
now=`date` 
echo now
結果會秀出今天的日期與時間

此外,雙引號與單引號字串對變數解釋有不同的意義,
如果是使用單引號,則變數會當成一般文字;雙引號才會解譯成變數,例如:
a=123
echo "$a" ->結果是123
echo '$a' ->結果是$a


Script也可以要求使用者輸入資料,利用read指令來讀取輸入的資料。如下:
#!/bin/sh
echo -n "Please input your name:"
read Name
echo "Your name is $Name"

由於echo指令預設會自動換行,所以我們使用參數-n 來不讓他換行。
我們將上述內容存成檔案test01.sh,接著執行它:
sh test01.sh
Please input your name: Danny ->提示要輸入名字,此時輸入的是Danny
Your name is Danny

Shell Script有一些預設的特殊變數如下:
$? :表示上一個指令的離開狀況,一般指令正常離開會傳回 0。不正常離開則會傳回 1、2 等數值。
$1 :表示輸入的第一個參數,$2 則為第二個參數,依此類推。
$0 :shell script的檔名。
$@ :即代表 $1, $2,....直到所有參數結束。也就是說 $@ 代表了 "$1" "$2" "$3"....。
$* :所有參數無間隔的連在一起,成為單一個參數。也就是說 $* 代表了 "$1 $2 $3..."

三、運算符號

在 shell 中的四則運算必須使用 expr 這個指令來輔助。注意,在 + - * / 的二邊都有空白,如果沒有空白將產生錯誤:
expr 6 - 2
sum=`expr 10 + 20`
echo $sum
結果:
4
30

還有要特別注意的是乘號 * 。因為 * 有其他意義,所以要使用 \* 來代表。另外,也可以用 % 來求餘數。
count=`expr 9 \* 3`
echo $count
echo `expr $count % 3`
結果:
27
0

簡單的條件判斷是以 && 及 || 這二個符號來表示。
a && b如果 a 是真,則執行 b。如果 a 是假,則不執行 b。
a || b如果 a 是假,則執行 b。如果 a 是真,則不執行 b。
例如:
ls /home && echo YES
ls /dev/aaaa && echo YES
結果:
YES
ls: /dev/aaaa: No such file or directory

接著我們使用 test 及 [ 來做運算,運算所傳回的結果是真 (true) 或假 ( false)。
我們可以將它應用在條件判斷上。test 和 [ 都是一個指令,我們可以使用 test 並在其後加上參數來判斷真假。
或者也可以使用 [ 表達式 ] 來替代 test,要注意的是 [ ] 中的必須有空白間隔。

表達式說明如下:
-n str1      :如果字串 str1 的長度大於 0 則傳回 true。
-z str1      :如果字串 str1 的長度等於 0 則傳回 true。
str1  = str2 :如果字串str1等於字串str2則傳回 true,等號二邊有空白。
str1 != str2 :如果 str1 不等於 str2 則傳回 true。!= 的二邊有空白。
a -eq b      :Equal,a 等於 b 則傳回真 (true)。
a -ne b      :Not equal,a 不等於 b 則傳回真 (true)。
a -gt b      :Grwater than,a 大於 b 則傳回真 (true)。
a -lt b      :Less Than,a 小於 b 則傳回真 (true)。
a -ge b      :Greater or equal,a 大於或等於 b 則傳回真 (true)。
a -le b      :Less or equal,a 小於或等於 b 則傳回真 (true)。

我們舉例來說明:
test 5 -eq 5 && echo true
test abc!=cde && echo true
[ 6 -lt 10 ] && echo true
結果:
true
true
true

四、流程控制

1、if 的條件判斷

範例:
if [ $1 = "aa" ]; then
  echo "YES"
else
  echo "NO"
fi

範例二:
#!/bin/sh
if [ $1 -gt 10 ]; then
      echo " $1 is bigger then 10"
elif [ $1 -ge 0 ]; then
      echo " $1 is between 5 and 0. "
else 
      echo "$1 is less then 0."
fi


2、while 及 until 迴圈
基本語法:
while condition-list
   do list
   done

until condition-list
   do list
   done
範例一:
#!/bin/sh
i=1
while [ $i -le 10 ]
   do
       echo $i
       i=$(($i+1))
   done
說明:首先令變數 i=1,接著在當i小於等於10執行迴圈的內容,而每次執行迴圈一次,則i加1。

範例二:
#!/bin/sh
i=1
until [ $i -gt 10 ]
   do
       echo $i
       i=$(($i+1))`
   done

說明:首先令變數 i=1,接著迴圈會判斷,一直執行到i大於10才停止。
      每跑一次迴圈就i就加1。
 
3、for 迴圈
基本語法:
for name in word1 word2 …
   do do-list
   done

for name
   do do-list
   done
  
範例一:
#!/bin/sh
for color_name in blue red green
    do
       echo $color_name
    done

說明:這個Script中,會在每一次迴圈中將關鍵字in後面的字串分配給變數color_name,
      然後印出變數 color。
 
4、case 判斷
基本語法:
case word in
    pattern1) list1 ;;
    pattern2) list2 ;;
    …
esac

範例:
case $num1 in
  1|2|3)       echo $num1 is between 0~3;;
  4|5|6|7)       echo $num1 is between 4~7;;
  8|9)           echo $num1 is 8 or 9;;
  *)             echo $num1 is not on the list;;
esac

6、函式的運用
Shell Script中也可以使用函式 (function) 來將程式模組化。
基本語法:
name ( )
{
    statement
}

函式有幾個要注意的地方:
  A、在使用函式之前一定要先定義它,也就是在一個 Shell Script 中,一定要先寫函式的內容,
     在函式之後再寫一般的程式部份。
  B、在Script中的變數全部都是全域變數 (Global),所以函式中的變數會影響函式之外的其他部份。
  C、在命令列中輸入的參數是以 $1,$2來讀取,但是這些參數並沒有辦法在函式中使用。
     傳給函式的方法和在命令列中一樣,例如:[函式名稱] arg1 arg2..。
 傳進函式的變數一樣會以 $1,$2來儲存並使用。

範例:
addnum1 ( )
{
  echo 'Function $1 is' $1
  echo 'Function $2 is' $2 
}

echo 'Command $1 is' $1
echo 'Command $2 is' $2

a=$(($1 + 10))
b=$(($2 + 10))
addnum1 $a $b

程式執行:
./test01.sh 2 3
結果:
Command $1 is 2
Command $2 is 3
Function $1 is 12
Function $2 is 13



五、Shell script Debug

可以使用以下的方式來做Debug用途
sh -x ./test.sh
他會印出test.sh實際運作的過程