Linux Shell——流程式控制制

来源:http://www.cnblogs.com/IcanFixIt/archive/2017/04/28/6782513.html
-Advertisement-
Play Games

一. 創建互動式腳本 使用 echo命令的選項 關於各種命令的使用,可以使用 來查看命令的詳細用法介紹。例如,我想看下 echo 的用法和各種選項。可以執行 。執行結果如下: 如果單獨執行 echo 命令,就會列印出一個空白行。 預設情況下,echo 都會換行,如果不想換行的話,可以使用下麵兩種方式 ...


Linux Shell

一. 創建互動式腳本

使用 echo命令的選項

關於各種命令的使用,可以使用man 命令來查看命令的詳細用法介紹。例如,我想看下 echo 的用法和各種選項。可以執行 man echo。執行結果如下:

echo

如果單獨執行 echo 命令,就會列印出一個空白行。
預設情況下,echo 都會換行,如果不想換行的話,可以使用下麵兩種方式的一種。

echo -n "Which directory do you want to use? "
echo -e "Which directory do you want to use? \c"

使用 read 命令

如果我們需要讀入用戶輸入的參數時,可以使用 read 命令,當然還可以從文件系統等讀入信息。
我們建立一個新的腳本文件 hello3.sh。

#!/bin/bash
echo -n "Hello I  $(basename $0) may I ask your name: "
read
echo "Hello $REPLY"
exit 0

執行此腳本時,首先提示需要輸入,然後輸入的內容,REPLY當沒有給read提供參數時設置,最後列印出來。

執行結果為:

hello3.sh

優化 read 提示的腳本

在前面的例子中,我們使用了echo -n的方式來阻止信息換行,其實 read 命令也帶了一個選項來實現相同的功能:

read -p "Enter your name: " name

上面的腳本中,我們定義了一個變數name用來保存輸入的內容,如果不定義變數的話,輸入的內容會保存在REPLY中。
下麵是具體使用的語法:
read -p

hello3.sh的腳本可以改成如下:

#!/bin/bash
read -p "May I ask your name: " name
echo "Hello $name"
exit 0

限制輸入內容的個數

我們還可以使用 read命令的-n 選項,此選項後面需要接一個數字,可以限制輸入內容的個數。

#!/bin/bash
read -p "May I ask your name: " name
echo "Hello $name"
read -n1 -p "Press any key to exit"
echo
exit 0

控制輸入內容的可見性

目前,我們輸入的內容都是可見的,但有些敏感的數據,如密碼,信用卡號等信息,輸入時並不想可見。那麼可以使用read -s

read -s

這時再輸入時,就有一個鑰匙的標識,而且輸入時不可見。

實例演示

現在有一個小程式,要求把指定尾碼的文件備份到指定的目錄下,代碼如下:

#!/bin/bash
# Script to prompt to back up files and location
# The files will be search on from the user's home
# directory and can only be backed up to a directory within $HOME

read -p "Which file types do you want to backup " file_suffix
read -p "Which directory do you want to backup to " dir_name

# The next lines creates the directory if it does not exist
test -d $HOME/$dir_name || mkdir -m 700 $HOME/$dir_name

# The find command will copy files the match the
# search criteria ie .sh . The -path, -prune and -o
# options are to exclude the back directory from the
# backup.
find $HOME -path $HOME/$dir_name -prune -o \
 -name "*$file_suffix" -exec cp {} $HOME/$dir_name/ \;

exit 0

二. 條件判斷語句

使用test 內建函數

test命令是 shell 環境中用於測試條件表達式的工具。
它的返回值可以是 true,false,0或1。基本語法為:

test EXPRESSION

如果我們需要多個表達式,可以使用ANDOR,對應的選項為-a-o

test EXPRESSION -a EXPRESSION
test EXPRESSION -o EXPRESSION

其實,在實際應用中,test 有種非常簡潔的方式,就是被中括弧包含的條件表達式。這種方式更加常用。語法如下:

[ EXPRESION ]

test 的用法很多,例如,可以比較兩個字元串是否相等:

[ $USER = root ]

我們還可以test 的選項來判斷一個字元串的長度是否為0。

[ -z $1 ]

上面的代碼的含義是,如果沒有參數輸入的話,返回 true。

test 還可以用來比較數字的大小。例如:

[ $# -gt 0 ]

除此而外,還可以判斷文件的類型。例如,我們想查找類型為符號鏈接的文件,然後刪除。可以使用如下腳本:

# [ -h $HOME/bin ] &&rm $HOME/bin

其他常用的選項如下:

  • -d:文件是否為目錄
  • -e:文件是否存在
  • -x:文件是否可以執行
  • -f:文件是否為常規文件
  • -r:文件是否可讀
  • -p:文件是否為命名管道
  • -b:文件是否為塊設備文件
  • -c:文件是否為字元設備文件

使用 if 條件判斷語句

if 語句的基本格式為:

if conditon ; then
    statement 1
    statement 2
fi

我們可以看一個具體的例子:

#!/bin/bash
if [ $# -lt 1 ] ; then
    echo "Usage: $0 <name>"
    exit 1
fi

echo "Hello $1"

exit 0

在運行此腳本時,如果沒有輸入參數,則提示正確的使用方法,非正常退出;否則,列印輸入的參數,程式正常退出。

if 語句還可以使用 else 條件分支。具體的語法為:

if conditon ; then
    statement
else
    statement
fi

我們新建一個腳本文件 hello6.sh,來展示 if else 的用法。

#!/bin/bash
if [ $# -lt 1 ] ; then
    read -p "Enter a name: "
    name=$REPLY
else
    name=$1
fi

echo "Hello $name"

exit 0

當沒有輸入參數時,程式提示需要輸入一個 name;如果輸入了的話,就會列印出來。

最後一種 if 的情況,也是最完整的 if 條件語句。語法如下;

if condition; then
    statement
elif condition; then
    statement
else
    statement
fi

再舉個例子,新建腳本 backup2.sh,我們使用 tar 命令來備份壓縮指定的目錄,根據輸入的參數“H”,“M”,“L”,可以執行不同的壓縮級別。

如果輸入的參數為“H”,則使用 bzip2的壓縮方式;

如果輸入的參數為“M”,則使用 gzip 的壓縮方式;

如果輸入的參數為“L”,則使用 tar 命令對文件打包,不壓縮。

#!/bin/bash
# this sciprt dirs’ location are defualt under $HOME

read -p "Choose H, M or L compression " file_compression
read -p "Which directory do you want to backup to " dir_name
read -p "Which directory do you went to backup: " tobe_backup_name

# The next lines creates the directory if it does not exist
test -d $HOME/$dir_name || mkdir -m 700 $HOME/$dir_name
backup_dir=$HOME/$dir_name

tar_l="-cvf  $backup_dir/b.tar $HOME/$tobe_backup_name"
tar_m="-czvf $backup_dir/b.tar.gz $HOME/$tobe_backup_name"
tar_h="-cjvf $backup_dir/b.tar.bzip2 $HOME/$tobe_backup_name"

if [ $file_compression = "L" ] ; then
    tar_opt=$tar_l
elif [ $file_compression = "M" ]; then
    tar_opt=$tar_m
else
    tar_opt=$tar_h
fi

tar $tar_opt

exit 0

使用 case 選擇語句

如果 if else 分支太多的話,可以考慮使用 case 語句,case 語句提供了更加簡潔的機制。
case 語句的語法結構為:

case expression in
    case1) 
        statement1
        statement2
    ;;
    case2)
        statement1
        statement2
   ;;
   *)
       statement1
   ;;
esac

還是舉個簡單的例子,新建腳本文件 grade.sh。

#!/bin/bash
# Script to evaluate grades
# Usage: grade.sh studentName grade

if [ ! $# -eq2 ] ; then
    echo "You must provide <studentName> <grade>
    exit 2
fi

case $2 in
    [A-C]|[a-c]) 
        echo "$1 is a star pupil"
    ;;
    [Dd]) 
        echo "$1 needs to try a little harder!"
    ;;
    [E-F]|[e-f]) 
        echo "$1 could do a lot better next year"
    ;;
    *) 
        echo "Grade could not be evaluated for $1"
esac

exit 0

運行結果如下:

grade

三. 一些註意事項

我們前面已經介紹過 test 內置命令用來判斷條件語句,但通常我們會推薦使用[]來替代 test 命令。例如:

[ -f /etc/hosts -a -r /etc/hosts ]

但這裡面有個問題,例如,下麵的腳本中,文件名中有空格,我們都知道,空格在命令行中有特殊的用處,用來分割命令選項和參數等。下麵的代碼會報錯。

FILE="my file"
[ -f $FILE -a -r $FILE ] && cat $FILE

報錯信息為“too many arguments”,原因是程式把帶有空格的文件名解析成了兩部分。
而這時,我們需要把變數用雙引號包含起來,

FILE="my file"
[ -f "$FILE" -a -r "$FILE" ] && cat "$FILE"

那有沒有好的辦法可以不使用雙引號呢?當然有的,那就是使用“[[”關鍵字。
“[[”並不是所有的 shell 都支持,它不相容Bourne Shell。我們可以用 type 命令來查看它的類型。

上面的腳本中的[]內的雙引號就可以不用了,但要註意的是 cat 里的雙引號還是要有的。

FILE="my file"
[[ -f $FILE && -r $FILE ]] && cat "$FILE"

“[[”還有其他高級的功能:

1. 模式匹配

例如,我們需要判斷 Perl 腳本,然後做其他的操作,那麼就可以這樣寫:

[[ $FILE = *.pl ]] && cp "$FILE" scripts/
2. 正則表達式

我們可以使用“=~”來匹配正則表達式。我們可以用正則表達式重寫上面的腳本。

$ [[ $FILE =~ \.pl$ ]] &&cp "$FILE" scripts/

我們還可以使用“(())”運算符來做一些簡單的運算。

1. 簡單的數學運算

我們可以使用“((”做一些簡單的數學運算,它可以替代 let 這個內置命令。下麵兩行的代碼執行結果是一樣的。

a=(( 2 + 3 ))
let a=2+3
2. 用在迴圈累加或累減中

這種方式更加常用,

COUNT=1
(( COUNT++ ))
echo $COUNT
3. 用於運算檢查中

我們也可以把“((”用在 test 判斷條件中,我們可以是用“>” 符號,來替代“-gt”。

(( COUNT > 1 )) && echo "Count is greater than 1"

四. 迭代迴圈

迴圈語句是任何一門語言都不能缺失的部分。shell 里也是一樣,只是語法不太一樣。如果學過其他的編程語言,就很容易掌握。

1. for 迴圈

for 迴圈的語法疾結構為:

for f in * ; do
    statement "$f"
done

這裡的 f 就是迭代的元素,* 可以是一個數組或是 list,也可以是命令管道。
還有另外一種寫法:

for f in * 
do
    statement "$f"
done

可以根據自己的喜好選擇一種寫法。
新建一個腳本文件,列印出所有輸入的參數:

#!/bin/bash
echo "You are using $(basename $0)"
for n in $*
do
    echo "Hello $n"
done

exit 0

運行結果如下:

for loop

在迴圈中,可以使用continuebreak關鍵字,具體用法與其他語言里是一樣的。continue表示在迴圈體內,跳過當前迴圈,執行下次的迴圈;而break表示退出整個迴圈,後面的迴圈和代碼不再執行。
看具體看例子。

$ for f in * ; do
    [ -d "$f" ] || continue
         chmod 3777 "$f"
done

如果是目錄,添加許可權;如果不是,跳過當前迴圈,continue 後面代碼不再執行,而是直接執行下次迴圈。

$ for f in * ; do
    [ -d "$f" ] && break
done

echo "We have found a directory $f"

上面的腳本,在迴圈中一旦發現目錄,則立即停止迴圈並退出。

2. while 迴圈

while 迴圈可以說是 for 迴圈的一個變體,只要特定條件為真,while 語句就會執行。具體看例子,

COUNT=10
while (( COUNT >= 0 )) ; do
    echo -e "$COUNT \c"
    (( COUNT-- ))
done ;

 echo

3. until 迴圈

until迴圈與while語句的功能正好相反:只要特定條件為假,它就重覆。下麵是一個與前面的 while 迴圈具有同等功能的 until 迴圈。

COUNT=10
until (( COUNT < 0 )) ; do
    echo -e "$COUNT \c"
    (( COUNT-- ))
done ; 

echo

4. 實例聯繫

現在,我們做一個用戶選擇界面,這樣,根據提示輸入不同的參數來執行不同的功能,這裡我們需要用到while迴圈,和前面講過的case條件選擇。

#!/bin/bash

while true ; do
    clear
    echo "Choose an item: a, b or c"
    echo "a: Backup"
    echo "b: Display Calendar"
    echo "c: Exit"
    
    read -sn1
        case "$REPLY" in
        a) tar -czvf $HOME/backup.tgz ${HOME}/JavaSource;;
        b) cal;;
        c) exit 0;;
        esac
    read -n1 -p "Press andy key to continue"
done

根據提示,如果輸入 a 的話,則把 home 目錄下的 JavaSource 目錄壓縮打包。
輸入b,顯示當前月份。
輸入c,程式退出。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在使用JDBC連接mysql時可能會遇到以下錯誤: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet sent successfully to th ...
  • 1. 忘記root密碼編輯mysql主配置文件 my.cnf 在[mysqld]欄位下添加參數 skip-grant ,重啟資料庫服務,這樣就可以進入資料庫不用授權了 mysql -uroot ,修改相應用戶密碼 use mysql; update user set password=passwor ...
  • 使用下麵的命令檢查是否安裝有MySQL Server 有的話,我們就通過 rpm -e 命令 或者 rpm -e --nodeps 命令來卸載掉 在刪除完以後我們可以通過 rpm -qa | grep mysql 命令來查看mysql是否已經卸載成功!! 官網yum repository 下載安裝包 ...
  • 背景 yarn預設使用的是最簡單的FIFO調度器,即一個default隊列,所有用戶共用,分配資源也是先到先得,沒有優先順序之分。有時一兩個任務就把資源全占了,其他任務吃不到資源造成饑餓,顯然這樣的資源分配是不合理的(在當今社會主義之中,我們要共同富裕啊)。yarn還有兩種資源調度器,capacity ...
  • 昨天收穫頗多,首先回顧一下有關mysql的內容。 我在查詢表信息時,出現了 empty set 0.00 sec 的錯誤,我很奇怪,仔細檢查發現原來是表欄位名稱寫錯了, 於是我想修改欄位名稱,經過查詢相關知識終於修改成功。 將表user 欄位 naem 修改為 name: ALTER TABLE u ...
  • 層次結構數據定義為一組通過層次結構關係互相關聯的數據項。 在層次結構關係中,一個數據項是另一個項的父級或子級。 sql server2008開始內置的 hierarchyid 數據類型使存儲和查詢層次結構數據變得更為容易。hierarchyid 其實是 CLR 數據類型。 廢話不多說,看不明白就實際 ...
  • 收錄待用,修改轉載已取得 "騰訊雲" 授權 昨天趁著周末把 "伺服器" 升級了一把,遇到的坑可不少: 坑1:升級失敗後,改用下麵命令: 坑2:若中間配置失敗,再可以執行: 坑3:若下載包資源失敗,則修改資源文件列表: 例如這是 "騰訊伺服器" 的: 坑4:這時再返回來執行 ,而不是 包下載完畢後會自 ...
  • 在我們實際工作中,好多時間需要經常性的進入某個目錄查看文件等等之類的操作。 好多時候我們都是在終端一級一級的進入目錄,相比較Windows的快捷方式有點繁瑣。 廢話少說,下麵就是設置快捷方式的方法: 在終端家目錄打開.bashrc 後者是.zshrc,任意位置輸入下麵的示例: 例:alias www ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...