中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

軟件源碼購買一般在哪個網(wǎng)站網(wǎng)址網(wǎng)域ip地址查詢

軟件源碼購買一般在哪個網(wǎng)站,網(wǎng)址網(wǎng)域ip地址查詢,商城網(wǎng)站如何做,鄢陵網(wǎng)站建設(shè)大家好,這里是 Lucifer三思而后行,專注于提升數(shù)據(jù)庫運維效率。 文章目錄 一篇文章讓你徹底掌握 Shell簡介什么是 shell什么是 shell 腳本Shell 環(huán)境指定腳本解釋器 模式交互模式非交互模式 基本語法解釋器注釋echoprintfprintf 的轉(zhuǎn)義符 變量變量命名原則…

大家好,這里是 Lucifer三思而后行,專注于提升數(shù)據(jù)庫運維效率。

文章目錄

  • 一篇文章讓你徹底掌握 Shell
  • 簡介
    • 什么是 shell
    • 什么是 shell 腳本
    • Shell 環(huán)境
      • 指定腳本解釋器
    • 模式
      • 交互模式
      • 非交互模式
    • 基本語法
      • 解釋器
      • 注釋
      • echo
      • printf
        • printf 的轉(zhuǎn)義符
    • 變量
      • 變量命名原則
      • 聲明變量
      • 只讀變量
      • 刪除變量
      • 變量類型
    • 字符串
      • 單引號和雙引號
      • 拼接字符串
      • 獲取字符串長度
      • 截取子字符串
    • 查找子字符串
    • 數(shù)組
      • 創(chuàng)建數(shù)組
      • 訪問數(shù)組元素
        • 訪問數(shù)組的單個元素
        • 訪問數(shù)組的所有元素
        • 訪問數(shù)組的部分元素
      • 訪問數(shù)組長度
      • 向數(shù)組中添加元素
      • 從數(shù)組中刪除元素
    • 運算符
      • 算術(shù)運算符
      • 關(guān)系運算符
      • 布爾運算符
      • 邏輯運算符
      • 字符串運算符
      • 文件測試運算符
    • 控制語句
      • 條件語句
        • if
        • case
      • 循環(huán)語句
        • for 循環(huán)
        • while 循環(huán)
        • until 循環(huán)
        • select 循環(huán)
        • break 和 continue
    • 函數(shù)
      • 位置參數(shù)
      • 函數(shù)處理參數(shù)
    • Shell 擴展
      • 大括號擴展
      • 命令置換
      • 算數(shù)擴展
      • 單引號和雙引號
    • 流和重定向
      • 輸入、輸出流
      • 重定向
      • /dev/null 文件
    • Debug
    • 往期精彩文章

一篇文章讓你徹底掌握 Shell

Bash 是 Linux 標(biāo)準默認的 shell 解釋器,可以說 bash 是 shell 編程的基礎(chǔ)。
本文主要介紹 bash 的語法,對于 Linux 指令不做任何介紹。

███████╗██╗  ██╗███████╗██╗     ██╗
██╔════╝██║  ██║██╔════╝██║     ██║
███████╗███████║█████╗  ██║     ██║
╚════██║██╔══██║██╔══╝  ██║     ██║
███████║██║  ██║███████╗███████╗███████╗
╚══════╝╚═╝  ╚═╝╚══════╝╚══════╝╚══════╝

簡介

什么是 shell

  • Shell 是一個用 C 語言編寫的程序,它是用戶使用 Linux 的橋梁。
  • Shell 既是一種命令語言,又是一種程序設(shè)計語言。
  • Shell 是指一種應(yīng)用程序,這個應(yīng)用程序提供了一個界面,用戶通過這個界面訪問 Linux 內(nèi)核的服務(wù)。

Ken Thompson 的 sh 是第一種 Unix Shell,Windows Explorer 是一個典型的圖形界面 Shell。

什么是 shell 腳本

Shell 腳本(shell script),是一種為 shell 編寫的腳本程序,一般文件后綴為 .sh。

業(yè)界所說的 shell 通常都是指 shell 腳本,但 shell 和 shell script 是兩個不同的概念。

Shell 環(huán)境

Shell 編程跟 java、php 編程一樣,只要有一個能編寫代碼的文本編輯器和一個能解釋執(zhí)行的腳本解釋器就可以了。

Shell 的解釋器種類眾多,常見的有:

  • sh - 即 Bourne Shell。sh 是 Unix 標(biāo)準默認的 shell。
  • bash - 即 Bourne Again Shell。bash 是 Linux 標(biāo)準默認的 shell。
  • fish - 智能和用戶友好的命令行 shell。
  • xiki - 使 shell 控制臺更友好,更強大。
  • zsh - 功能強大的 shell 與腳本語言。

指定腳本解釋器

在 shell 腳本,#! 告訴系統(tǒng)其后路徑所指定的程序即是解釋此腳本文件的 Shell 解釋器。#! 被稱作 shebang(也稱為 Hashbang )。

所以,你應(yīng)該會在 shell 中,見到諸如以下的注釋:

指定 sh 解釋器:

#!/bin/sh

指定 bash 解釋器:

#!/bin/bash

注意: 上面的指定解釋器的方式是比較常見的,但有時候,你可能也會看到下面的方式:

#!/usr/bin/env bash

這樣做的好處是,系統(tǒng)會自動在 PATH 環(huán)境變量中查找你指定的程序(本例中的 bash)。相比第一種寫法,你應(yīng)該盡量用這種寫法,因為程序的路徑是不確定的。這樣寫還有一個好處,操作系統(tǒng)的 PATH 變量有可能被配置為指向程序的另一個版本。比如,安裝完新版本的 bash,我們可能將其路徑添加到 PATH 中,來“隱藏”老版本。如果直接用 #!/bin/bash,那么系統(tǒng)會選擇老版本的 bash 來執(zhí)行腳本,如果用 #!/usr/bin/env bash,則會使用新版本。

模式

shell 有交互和非交互兩種模式。

交互模式

簡單來說,你可以將 shell 的交互模式理解為執(zhí)行命令行。

看到形如下面的東西,說明 shell 處于交互模式下:

user@host:~$

接著,便可以輸入一系列 Linux 命令,比如 ls,grep,cd,mkdir,rm 等等。

非交互模式

簡單來說,你可以將 shell 的非交互模式理解為執(zhí)行 shell 腳本。

在非交互模式下,shell 從文件或者管道中讀取命令并執(zhí)行。

當(dāng) shell 解釋器執(zhí)行完文件中的最后一個命令,shell 進程終止,并回到父進程。

可以使用下面的命令讓 shell 以非交互模式運行:

sh /path/to/script.sh
bash /path/to/script.sh
source /path/to/script.sh
./path/to/script.sh

上面的例子中,script.sh 是一個包含 shell 解釋器可以識別并執(zhí)行的命令的普通文本文件,sh 和 bash 是 shell 解釋器程序。你可以使用任何喜歡的編輯器創(chuàng)建 script.sh(vim,nano,Sublime Text, Atom 等等)。

其中,source /path/to/script.sh./path/to/script.sh 是等價的。

除此之外,你還可以通過 chmod 命令給文件添加可執(zhí)行的權(quán)限,來直接執(zhí)行腳本文件:

chmod +x /path/to/script.sh #使腳本具有執(zhí)行權(quán)限
/path/to/test.sh

這種方式要求腳本文件的第一行必須指明運行該腳本的程序,比如:

💻 “示例源碼”:

#!/usr/bin/env bash
echo "Hello, world!"

上面的例子中,我們使用了一個很有用的命令 echo 來輸出字符串到屏幕上。

基本語法

解釋器

前面雖然兩次提到了 #! ,但是本著重要的事情說三遍的精神,這里再強調(diào)一遍:

在 shell 腳本,#! 告訴系統(tǒng)其后路徑所指定的程序即是解釋此腳本文件的 Shell 解釋器。#! 被稱作 shebang(也稱為 Hashbang )。

#! 決定了腳本可以像一個獨立的可執(zhí)行文件一樣執(zhí)行,而不用在終端之前輸入 sh, bash, python, php 等。

# 以下兩種方式都可以指定 shell 解釋器為 bash,第二種方式更好
#!/bin/bash
#!/usr/bin/env bash

注釋

注釋可以說明你的代碼是什么作用,以及為什么這樣寫。

shell 語法中,注釋是特殊的語句,會被 shell 解釋器忽略。

  • 單行注釋 - 以 # 開頭,到行尾結(jié)束。
  • 多行注釋 - 以 :<<EOF 開頭,到 EOF 結(jié)束。

💻 “示例源碼”:

#--------------------------------------------
# shell 注釋示例
# author:zp
#--------------------------------------------# echo '這是單行注釋'########## 這是分割線 ##########:<<EOF
echo '這是多行注釋'
echo '這是多行注釋'
echo '這是多行注釋'
EOF

echo

echo 用于字符串的輸出。

輸出普通字符串:

echo "hello, world"
# Output: hello, world

輸出含變量的字符串:

echo "hello, \"zp\""
# Output: hello, "zp"

輸出含變量的字符串:

name=zp
echo "hello, \"${name}\""
# Output: hello, "zp"

輸出含換行符的字符串:

# 輸出含換行符的字符串
echo "YES\nNO"
#  Output: YES\nNOecho -e "YES\nNO" # -e 開啟轉(zhuǎn)義
#  Output:
#  YES
#  NO

輸出含不換行符的字符串:

echo "YES"
echo "NO"
#  Output:
#  YES
#  NOecho -e "YES\c" # -e 開啟轉(zhuǎn)義 \c 不換行
echo "NO"
#  Output:
#  YESNO

輸出重定向至文件:

echo "test" > test.txt

輸出執(zhí)行結(jié)果:

echo `pwd`
#  Output:(當(dāng)前目錄路徑)

💻 “示例源碼”:

#!/usr/bin/env bash# 輸出普通字符串
echo "hello, world"
#  Output: hello, world# 輸出含變量的字符串
echo "hello, \"zp\""
#  Output: hello, "zp"# 輸出含變量的字符串
name=zp
echo "hello, \"${name}\""
#  Output: hello, "zp"# 輸出含換行符的字符串
echo "YES\nNO"
#  Output: YES\nNO
echo -e "YES\nNO" # -e 開啟轉(zhuǎn)義
#  Output:
#  YES
#  NO# 輸出含不換行符的字符串
echo "YES"
echo "NO"
#  Output:
#  YES
#  NOecho -e "YES\c" # -e 開啟轉(zhuǎn)義 \c 不換行
echo "NO"
#  Output:
#  YESNO# 輸出內(nèi)容定向至文件
echo "test" > test.txt# 輸出執(zhí)行結(jié)果
echo `pwd`
#  Output:(當(dāng)前目錄路徑)

printf

printf 用于格式化輸出字符串。

默認,printf 不會像 echo 一樣自動添加換行符,如果需要換行可以手動添加 \n。

💻 “示例源碼”:

# 單引號
printf '%d %s\n' 1 "abc"
#  Output:1 abc# 雙引號
printf "%d %s\n" 1 "abc"
#  Output:1 abc# 無引號
printf %s abcdef
#  Output: abcdef(并不會換行)# 格式只指定了一個參數(shù),但多出的參數(shù)仍然會按照該格式輸出
printf "%s\n" abc def
#  Output:
#  abc
#  defprintf "%s %s %s\n" a b c d e f g h i j
#  Output:
#  a b c
#  d e f
#  g h i
#  j# 如果沒有參數(shù),那么 %s 用 NULL 代替,%d 用 0 代替
printf "%s and %d \n"
#  Output:
#   and 0# 格式化輸出
printf "%-10s %-8s %-4s\n" 姓名 性別 體重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 楊過 男 48.6543
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
#  Output:
#  姓名     性別   體重kg
#  郭靖     男      66.12
#  楊過     男      48.65
#  郭芙     女      47.99
printf 的轉(zhuǎn)義符
序列說明
\a警告字符,通常為 ASCII 的 BEL 字符
\b后退
\c抑制(不顯示)輸出結(jié)果中任何結(jié)尾的換行字符(只在%b 格式指示符控制下的參數(shù)字符串中有效),而且,任何留在參數(shù)里的字符、任何接下來的參數(shù)以及任何留在格式字符串中的字符,都被忽略
\f換頁(formfeed)
\n換行
\r回車(Carriage return)
\t水平制表符
\v垂直制表符
\\一個字面上的反斜杠字符
\ddd表示 1 到 3 位數(shù)八進制值的字符。僅在格式字符串中有效
\0ddd表示 1 到 3 位的八進制值字符

變量

跟許多程序設(shè)計語言一樣,你可以在 bash 中創(chuàng)建變量。

Bash 中沒有數(shù)據(jù)類型,bash 中的變量可以保存一個數(shù)字、一個字符、一個字符串等等。同時無需提前聲明變量,給變量賦值會直接創(chuàng)建變量。

變量命名原則

  • 命名只能使用英文字母,數(shù)字和下劃線,首個字符不能以數(shù)字開頭。
  • 中間不能有空格,可以使用下劃線(_)。
  • 不能使用標(biāo)點符號。
  • 不能使用 bash 里的關(guān)鍵字(可用 help 命令查看保留關(guān)鍵字)。

聲明變量

訪問變量的語法形式為:${var}$var 。

變量名外面的花括號是可選的,加不加都行,加花括號是為了幫助解釋器識別變量的邊界,所以推薦加花括號。

word="hello"
echo ${word}
# Output: hello

只讀變量

使用 readonly 命令可以將變量定義為只讀變量,只讀變量的值不能被改變。

rword="hello"
echo ${rword}
readonly rword
# rword="bye"  # 如果放開注釋,執(zhí)行時會報錯

刪除變量

使用 unset 命令可以刪除變量。變量被刪除后不能再次使用。unset 命令不能刪除只讀變量。

dword="hello"  # 聲明變量
echo ${dword}  # 輸出變量值
# Output: hellounset dword    # 刪除變量
echo ${dword}
# Output: (空)

變量類型

  • 局部變量 - 局部變量是僅在某個腳本內(nèi)部有效的變量。它們不能被其他的程序和腳本訪問。
  • 環(huán)境變量 - 環(huán)境變量是對當(dāng)前 shell 會話內(nèi)所有的程序或腳本都可見的變量。創(chuàng)建它們跟創(chuàng)建局部變量類似,但使用的是 export 關(guān)鍵字,shell 腳本也可以定義環(huán)境變量。

常見的環(huán)境變量:

變量描述
$HOME當(dāng)前用戶的用戶目錄
$PATH用分號分隔的目錄列表,shell 會到這些目錄中查找命令
$PWD當(dāng)前工作目錄
$RANDOM0 到 32767 之間的整數(shù)
$UID數(shù)值類型,當(dāng)前用戶的用戶 ID
$PS1主要系統(tǒng)輸入提示符
$PS2次要系統(tǒng)輸入提示符

這里 有一張更全面的 Bash 環(huán)境變量列表。

💻 “示例源碼”:

#!/usr/bin/env bash################### 聲明變量 ###################
name="world"
echo "hello ${name}"
# Output: hello world################### 輸出變量 ###################
folder=$(pwd)
echo "current path: ${folder}"################### 只讀變量 ###################
rword="hello"
echo ${rword}
# Output: hello
readonly rword
# rword="bye"  # 如果放開注釋,執(zhí)行時會報錯################### 刪除變量 ###################
dword="hello" # 聲明變量
echo ${dword} # 輸出變量值
# Output: hellounset dword # 刪除變量
echo ${dword}
# Output: (空)################### 系統(tǒng)變量 ###################
echo "UID:$UID"
echo LOGNAME:$LOGNAME
echo User:$USER
echo HOME:$HOME
echo PATH:$PATH
echo HOSTNAME:$HOSTNAME
echo SHELL:$SHELL
echo LANG:$LANG################### 自定義變量 ###################
days=10
user="admin"
echo "$user logged in $days days age"
days=5
user="root"
echo "$user logged in $days days age"
# Output:
# admin logged in 10 days age
# root logged in 5 days age################### 從變量讀取列表 ###################
colors="Red Yellow Blue"
colors=$colors" White Black"for color in $colors
doecho " $color"
done

字符串

單引號和雙引號

shell 字符串可以用單引號 ‘’,也可以用雙引號 “”,也可以不用引號。

  • 單引號的特點 - 單引號里不識別變量 - 單引號里不能出現(xiàn)單獨的單引號(使用轉(zhuǎn)義符也不行),但可成對出現(xiàn),作為字符串拼接使用。
  • 雙引號的特點 - 雙引號里識別變量 - 雙引號里可以出現(xiàn)轉(zhuǎn)義字符

綜上,推薦使用雙引號。

拼接字符串

# 使用單引號拼接
name1='white'
str1='hello, '${name1}''
str2='hello, ${name1}'
echo ${str1}_${str2}
# Output:
# hello, white_hello, ${name1}# 使用雙引號拼接
name2="black"
str3="hello, "${name2}""
str4="hello, ${name2}"
echo ${str3}_${str4}
# Output:
# hello, black_hello, black

獲取字符串長度

text="12345"
echo ${#text}
# Output:
# 5

截取子字符串

text="12345"
echo ${text:2:2}
# Output:
# 34

從第 3 個字符開始,截取 2 個字符。

查找子字符串

#!/usr/bin/env bashtext="hello"
echo `expr index "${text}" ll`# Execute: ./str-demo5.sh
# Output:
# 3

查找 ll 子字符在 hello 字符串中的起始位置。

💻 “示例源碼”:

#!/usr/bin/env bash################### 使用單引號拼接字符串 ###################
name1='white'
str1='hello, '${name1}''
str2='hello, ${name1}'
echo ${str1}_${str2}
# Output:
# hello, white_hello, ${name1}################### 使用雙引號拼接字符串 ###################
name2="black"
str3="hello, "${name2}""
str4="hello, ${name2}"
echo ${str3}_${str4}
# Output:
# hello, black_hello, black################### 獲取字符串長度 ###################
text="12345"
echo "${text} length is: ${#text}"
# Output:
# 12345 length is: 5# 獲取子字符串
text="12345"
echo ${text:2:2}
# Output:
# 34################### 查找子字符串 ###################
text="hello"
echo `expr index "${text}" ll`
# Output:
# 3################### 判斷字符串中是否包含子字符串 ###################
result=$(echo "${str}" | grep "feature/")
if [[ "$result" != "" ]]; thenecho "feature/ 是 ${str} 的子字符串"
elseecho "feature/ 不是 ${str} 的子字符串"
fi################### 截取關(guān)鍵字左邊內(nèi)容 ###################
full_branch="feature/1.0.0"
branch=`echo ${full_branch#feature/}`
echo "branch is ${branch}"################### 截取關(guān)鍵字右邊內(nèi)容 ###################
full_version="0.0.1-SNAPSHOT"
version=`echo ${full_version%-SNAPSHOT}`
echo "version is ${version}"################### 字符串分割成數(shù)組 ###################
str="0.0.0.1"
OLD_IFS="$IFS"
IFS="."
array=( ${str} )
IFS="$OLD_IFS"
size=${#array[*]}
lastIndex=`expr ${size} - 1`
echo "數(shù)組長度:${size}"
echo "最后一個數(shù)組元素:${array[${lastIndex}]}"
for item in ${array[@]}
doecho "$item"
done################### 判斷字符串是否為空 ###################
#-n 判斷長度是否非零
#-z 判斷長度是否為零str=testing
str2=''
if [[ -n "$str" ]]
thenecho "The string $str is not empty"
elseecho "The string $str is empty"
fiif [[ -n "$str2" ]]
thenecho "The string $str2 is not empty"
elseecho "The string $str2 is empty"
fi#	Output:
#	The string testing is not empty
#	The string  is empty################### 字符串比較 ###################
str=hello
str2=world
if [[ $str = "hello" ]]; thenecho "str equals hello"
elseecho "str not equals hello"
fiif [[ $str2 = "hello" ]]; thenecho "str2 equals hello"
elseecho "str2 not equals hello"
fi

數(shù)組

bash 只支持一維數(shù)組。

數(shù)組下標(biāo)從 0 開始,下標(biāo)可以是整數(shù)或算術(shù)表達式,其值應(yīng)大于或等于 0。

創(chuàng)建數(shù)組

# 創(chuàng)建數(shù)組的不同方式
nums=([2]=2 [0]=0 [1]=1)
colors=(red yellow "dark blue")

訪問數(shù)組元素

訪問數(shù)組的單個元素
echo ${nums[1]}
# Output: 1
訪問數(shù)組的所有元素
echo ${colors[*]}
# Output: red yellow dark blueecho ${colors[@]}
# Output: red yellow dark blue

上面兩行有很重要(也很微妙)的區(qū)別:

為了將數(shù)組中每個元素單獨一行輸出,我們用 printf 命令:

printf "+ %s\n" ${colors[*]}
# Output:
# + red
# + yellow
# + dark
# + blue

為什么 dark 和 blue 各占了一行?嘗試用引號包起來:

printf "+ %s\n" "${colors[*]}"
# Output:
# + red yellow dark blue

現(xiàn)在所有的元素都在一行輸出 —— 這不是我們想要的!讓我們試試 ${colors[@]}

printf "+ %s\n" "${colors[@]}"
# Output:
# + red
# + yellow
# + dark blue

在引號內(nèi),${colors[@]}將數(shù)組中的每個元素擴展為一個單獨的參數(shù);數(shù)組元素中的空格得以保留。

訪問數(shù)組的部分元素
echo ${nums[@]:0:2}
# Output:
# 0 1

在上面的例子中,${array[@]} 擴展為整個數(shù)組,:0:2 取出了數(shù)組中從 0 開始,長度為 2 的元素。

訪問數(shù)組長度

echo ${#nums[*]}
# Output:
# 3

向數(shù)組中添加元素

向數(shù)組中添加元素也非常簡單:

colors=(white "${colors[@]}" green black)
echo ${colors[@]}
# Output:
# white red yellow dark blue green black

上面的例子中,${colors[@]} 擴展為整個數(shù)組,并被置換到復(fù)合賦值語句中,接著,對數(shù)組 colors 的賦值覆蓋了它原來的值。

從數(shù)組中刪除元素

用 unset 命令來從數(shù)組中刪除一個元素:

unset nums[0]
echo ${nums[@]}
# Output:
# 1 2

💻 “示例源碼”:

#!/usr/bin/env bash################### 創(chuàng)建數(shù)組 ###################
nums=( [ 2 ] = 2 [ 0 ] = 0 [ 1 ] = 1 )
colors=( red yellow "dark blue" )################### 訪問數(shù)組的單個元素 ###################
echo ${nums[1]}
# Output: 1################### 訪問數(shù)組的所有元素 ###################
echo ${colors[*]}
# Output: red yellow dark blueecho ${colors[@]}
# Output: red yellow dark blueprintf "+ %s\n" ${colors[*]}
# Output:
# + red
# + yellow
# + dark
# + blueprintf "+ %s\n" "${colors[*]}"
# Output:
# + red yellow dark blueprintf "+ %s\n" "${colors[@]}"
# Output:
# + red
# + yellow
# + dark blue################### 訪問數(shù)組的部分元素 ###################
echo ${nums[@]:0:2}
# Output:
# 0 1################### 獲取數(shù)組長度 ###################
echo ${#nums[*]}
# Output:
# 3################### 向數(shù)組中添加元素 ###################
colors=( white "${colors[@]}" green black )
echo ${colors[@]}
# Output:
# white red yellow dark blue green black################### 從數(shù)組中刪除元素 ###################
unset nums[ 0 ]
echo ${nums[@]}
# Output:
# 1 2

運算符

算術(shù)運算符

下表列出了常用的算術(shù)運算符,假定變量 x 為 10,變量 y 為 20:

運算符說明舉例
+加法expr $x + $y 結(jié)果為 30。
-減法expr $x - $y 結(jié)果為 -10。
*乘法expr $x * $y 結(jié)果為 200。
/除法expr $y / $x 結(jié)果為 2。
%取余expr $y % $x 結(jié)果為 0。
=賦值x=$y 將把變量 y 的值賦給 x。
==相等。用于比較兩個數(shù)字,相同則返回 true。[ $x == $y ] 返回 false。
!=不相等。用于比較兩個數(shù)字,不相同則返回 true。[ $x != $y ] 返回 true。

注意:條件表達式要放在方括號之間,并且要有空格,例如: [ x = = x== x==y] 是錯誤的,必須寫成 [ $x == $y ]。

💻 “示例源碼”:

x=10
y=20echo "x=${x}, y=${y}"val=`expr ${x} + ${y}`
echo "${x} + ${y} = $val"val=`expr ${x} - ${y}`
echo "${x} - ${y} = $val"val=`expr ${x} \* ${y}`
echo "${x} * ${y} = $val"val=`expr ${y} / ${x}`
echo "${y} / ${x} = $val"val=`expr ${y} % ${x}`
echo "${y} % ${x} = $val"if [[ ${x} == ${y} ]]
thenecho "${x} = ${y}"
fi
if [[ ${x} != ${y} ]]
thenecho "${x} != ${y}"
fi#  Output:
#  x=10, y=20
#  10 + 20 = 30
#  10 - 20 = -10
#  10 * 20 = 200
#  20 / 10 = 2
#  20 % 10 = 0
#  10 != 20

關(guān)系運算符

關(guān)系運算符只支持數(shù)字,不支持字符串,除非字符串的值是數(shù)字。

下表列出了常用的關(guān)系運算符,假定變量 x 為 10,變量 y 為 20:

運算符說明舉例
-eq檢測兩個數(shù)是否相等,相等返回 true。[ $a -eq $b ] 返回 false。
-ne檢測兩個數(shù)是否相等,不相等返回 true。[ $a -ne $b ] 返回 true。
-gt檢測左邊的數(shù)是否大于右邊的,如果是,則返回 true。[ $a -gt $b ] 返回 false。
-lt檢測左邊的數(shù)是否小于右邊的,如果是,則返回 true。[ $a -lt $b ] 返回 true。
-ge檢測左邊的數(shù)是否大于等于右邊的,如果是,則返回 true。[ $a -ge $b ] 返回 false。
-le檢測左邊的數(shù)是否小于等于右邊的,如果是,則返回 true。[ $a -le $b ] 返回 true。

💻 “示例源碼”:

x=10
y=20echo "x=${x}, y=${y}"if [[ ${x} -eq ${y} ]]; thenecho "${x} -eq ${y} : x 等于 y"
elseecho "${x} -eq ${y}: x 不等于 y"
fiif [[ ${x} -ne ${y} ]]; thenecho "${x} -ne ${y}: x 不等于 y"
elseecho "${x} -ne ${y}: x 等于 y"
fiif [[ ${x} -gt ${y} ]]; thenecho "${x} -gt ${y}: x 大于 y"
elseecho "${x} -gt ${y}: x 不大于 y"
fiif [[ ${x} -lt ${y} ]]; thenecho "${x} -lt ${y}: x 小于 y"
elseecho "${x} -lt ${y}: x 不小于 y"
fiif [[ ${x} -ge ${y} ]]; thenecho "${x} -ge ${y}: x 大于或等于 y"
elseecho "${x} -ge ${y}: x 小于 y"
fiif [[ ${x} -le ${y} ]]; thenecho "${x} -le ${y}: x 小于或等于 y"
elseecho "${x} -le ${y}: x 大于 y"
fi#  Output:
#  x=10, y=20
#  10 -eq 20: x 不等于 y
#  10 -ne 20: x 不等于 y
#  10 -gt 20: x 不大于 y
#  10 -lt 20: x 小于 y
#  10 -ge 20: x 小于 y
#  10 -le 20: x 小于或等于 y

布爾運算符

下表列出了常用的布爾運算符,假定變量 x 為 10,變量 y 為 20:

運算符說明舉例
!非運算,表達式為 true 則返回 false,否則返回 true。[ ! false ] 返回 true。
-o或運算,有一個表達式為 true 則返回 true。[ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a與運算,兩個表達式都為 true 才返回 true。[ $a -lt 20 -a $b -gt 100 ] 返回 false。

💻 “示例源碼”:

x=10
y=20echo "x=${x}, y=${y}"if [[ ${x} != ${y} ]]; thenecho "${x} != ${y} : x 不等于 y"
elseecho "${x} != ${y}: x 等于 y"
fiif [[ ${x} -lt 100 && ${y} -gt 15 ]]; thenecho "${x} 小于 100 且 ${y} 大于 15 : 返回 true"
elseecho "${x} 小于 100 且 ${y} 大于 15 : 返回 false"
fiif [[ ${x} -lt 100 || ${y} -gt 100 ]]; thenecho "${x} 小于 100 或 ${y} 大于 100 : 返回 true"
elseecho "${x} 小于 100 或 ${y} 大于 100 : 返回 false"
fiif [[ ${x} -lt 5 || ${y} -gt 100 ]]; thenecho "${x} 小于 5 或 ${y} 大于 100 : 返回 true"
elseecho "${x} 小于 5 或 ${y} 大于 100 : 返回 false"
fi#  Output:
#  x=10, y=20
#  10 != 20 : x 不等于 y
#  10 小于 100 且 20 大于 15 : 返回 true
#  10 小于 100 或 20 大于 100 : 返回 true
#  10 小于 5 或 20 大于 100 : 返回 false

邏輯運算符

以下介紹 Shell 的邏輯運算符,假定變量 x 為 10,變量 y 為 20:

運算符說明舉例
&&邏輯的 AND[[ ${x} -lt 100 && ${y} -gt 100 ]] 返回 false
``

💻 “示例源碼”:

x=10
y=20echo "x=${x}, y=${y}"if [[ ${x} -lt 100 && ${y} -gt 100 ]]
thenecho "${x} -lt 100 && ${y} -gt 100 返回 true"
elseecho "${x} -lt 100 && ${y} -gt 100 返回 false"
fiif [[ ${x} -lt 100 || ${y} -gt 100 ]]
thenecho "${x} -lt 100 || ${y} -gt 100 返回 true"
elseecho "${x} -lt 100 || ${y} -gt 100 返回 false"
fi#  Output:
#  x=10, y=20
#  10 -lt 100 && 20 -gt 100 返回 false
#  10 -lt 100 || 20 -gt 100 返回 true

字符串運算符

下表列出了常用的字符串運算符,假定變量 a 為 “abc”,變量 b 為 “efg”:

運算符說明舉例
=檢測兩個字符串是否相等,相等返回 true。[ $a = $b ] 返回 false。
!=檢測兩個字符串是否相等,不相等返回 true。[ $a != $b ] 返回 true。
-z檢測字符串長度是否為 0,為 0 返回 true。[ -z $a ] 返回 false。
-n檢測字符串長度是否為 0,不為 0 返回 true。[ -n $a ] 返回 true。
str檢測字符串是否為空,不為空返回 true。(注:這可能是一個誤解,因為str不是標(biāo)準的 shell 測試運算符。正確的可能是 -n[[ ]] 測試。)[ $a ] 返回 true。

💻 “示例源碼”:

x="abc"
y="xyz"echo "x=${x}, y=${y}"if [[ ${x} = ${y} ]]; thenecho "${x} = ${y} : x 等于 y"
elseecho "${x} = ${y}: x 不等于 y"
fiif [[ ${x} != ${y} ]]; thenecho "${x} != ${y} : x 不等于 y"
elseecho "${x} != ${y}: x 等于 y"
fiif [[ -z ${x} ]]; thenecho "-z ${x} : 字符串長度為 0"
elseecho "-z ${x} : 字符串長度不為 0"
fiif [[ -n "${x}" ]]; thenecho "-n ${x} : 字符串長度不為 0"
elseecho "-n ${x} : 字符串長度為 0"
fiif [[ ${x} ]]; thenecho "${x} : 字符串不為空"
elseecho "${x} : 字符串為空"
fi#  Output:
#  x=abc, y=xyz
#  abc = xyz: x 不等于 y
#  abc != xyz : x 不等于 y
#  -z abc : 字符串長度不為 0
#  -n abc : 字符串長度不為 0
#  abc : 字符串不為空

文件測試運算符

文件測試運算符用于檢測 Unix 文件的各種屬性。

屬性檢測描述如下:

操作符說明舉例
-b檢測文件是否是塊設(shè)備文件,如果是,則返回 true。[ -b $file ] 返回 false。
-c檢測文件是否是字符設(shè)備文件,如果是,則返回 true。[ -c $file ] 返回 false。
-d檢測文件是否是目錄,如果是,則返回 true。[ -d $file ] 返回 false。
-f檢測文件是否是普通文件(既不是目錄,也不是設(shè)備文件),如果是,則返回 true。[ -f $file ] 返回 true。
-g檢測文件是否設(shè)置了 SGID 位,如果是,則返回 true。[ -g $file ] 返回 false。
-k檢測文件是否設(shè)置了粘著位(Sticky Bit),如果是,則返回 true。[ -k $file ] 返回 false。
-p檢測文件是否是有名管道,如果是,則返回 true。[ -p $file ] 返回 false。
-u檢測文件是否設(shè)置了 SUID 位,如果是,則返回 true。[ -u $file ] 返回 false。
-r檢測文件是否可讀,如果是,則返回 true。[ -r $file ] 返回 true。
-w檢測文件是否可寫,如果是,則返回 true。[ -w $file ] 返回 true。
-x檢測文件是否可執(zhí)行,如果是,則返回 true。[ -x $file ] 返回 true。
-s檢測文件是否為空(文件大小是否大于 0),不為空返回 true。[ -s $file ] 返回 true。
-e檢測文件(包括目錄)是否存在,如果是,則返回 true。[ -e $file ] 返回 true。

💻 “示例源碼”:

file="/etc/hosts"if [[ -r ${file} ]]; thenecho "${file} 文件可讀"
elseecho "${file} 文件不可讀"
fi
if [[ -w ${file} ]]; thenecho "${file} 文件可寫"
elseecho "${file} 文件不可寫"
fi
if [[ -x ${file} ]]; thenecho "${file} 文件可執(zhí)行"
elseecho "${file} 文件不可執(zhí)行"
fi
if [[ -f ${file} ]]; thenecho "${file} 文件為普通文件"
elseecho "${file} 文件為特殊文件"
fi
if [[ -d ${file} ]]; thenecho "${file} 文件是個目錄"
elseecho "${file} 文件不是個目錄"
fi
if [[ -s ${file} ]]; thenecho "${file} 文件不為空"
elseecho "${file} 文件為空"
fi
if [[ -e ${file} ]]; thenecho "${file} 文件存在"
elseecho "${file} 文件不存在"
fi#  Output:(根據(jù)文件的實際情況,輸出結(jié)果可能不同)
#  /etc/hosts 文件可讀
#  /etc/hosts 文件可寫
#  /etc/hosts 文件不可執(zhí)行
#  /etc/hosts 文件為普通文件
#  /etc/hosts 文件不是個目錄
#  /etc/hosts 文件不為空
#  /etc/hosts 文件存在

控制語句

條件語句

跟其它程序設(shè)計語言一樣,Bash 中的條件語句讓我們可以決定一個操作是否被執(zhí)行。結(jié)果取決于一個包在[[ ]]里的表達式。

由[[ ]](sh 中是[ ])包起來的表達式被稱作 檢測命令 或 基元。這些表達式幫助我們檢測一個條件的結(jié)果。這里可以找到有關(guān) bash 中單雙中括號區(qū)別的答案。

共有兩個不同的條件表達式:if 和 case。

if

(1)if 語句

if 在使用上跟其它語言相同。如果中括號里的表達式為真,那么 then 和 fi 之間的代碼會被執(zhí)行。fi 標(biāo)志著條件代碼塊的結(jié)束。

# 寫成一行
if [[ 1 -eq 1 ]]; then echo "1 -eq 1 result is: true"; fi
# Output: 1 -eq 1 result is: true# 寫成多行
if [[ "abc" -eq "abc" ]]
thenecho ""abc" -eq "abc" result is: true"
fi
# Output: abc -eq abc result is: true

(2)if else 語句

同樣,我們可以使用 if…else 語句,例如:

if [[ 2 -ne 1 ]]; thenecho "true"
elseecho "false"
fi
# Output: true

(3)if elif else 語句

有些時候,if…else 不能滿足我們的要求。別忘了 if…elif…else,使用起來也很方便。

💻 “示例源碼”:

x=10
y=20
if [[ ${x} > ${y} ]]; thenecho "${x} > ${y}"
elif [[ ${x} < ${y} ]]; thenecho "${x} < ${y}"
elseecho "${x} = ${y}"
fi
# Output: 10 < 20
case

如果你需要面對很多情況,分別要采取不同的措施,那么使用 case 會比嵌套的 if 更有用。使用 case 來解決復(fù)雜的條件判斷,看起來像下面這樣:

💻 “示例源碼”:

exec
case ${oper} in"+")val=`expr ${x} + ${y}`echo "${x} + ${y} = ${val}";;"-")val=`expr ${x} - ${y}`echo "${x} - ${y} = ${val}";;"*")val=`expr ${x} \* ${y}`echo "${x} * ${y} = ${val}";;"/")val=`expr ${x} / ${y}`echo "${x} / ${y} = ${val}";;*)echo "Unknown oper!";;
esac

每種情況都是匹配了某個模式的表達式。|用來分割多個模式,)用來結(jié)束一個模式序列。第一個匹配上的模式對應(yīng)的命令將會被執(zhí)行。*代表任何不匹配以上給定模式的模式。命令塊兒之間要用;;分隔。

循環(huán)語句

循環(huán)其實不足為奇。跟其它程序設(shè)計語言一樣,bash 中的循環(huán)也是只要控制條件為真就一直迭代執(zhí)行的代碼塊。

Bash 中有四種循環(huán):

  • for
  • while
  • until
  • select
for 循環(huán)

for 與它在 C 語言中的姊妹非常像??雌饋硎沁@樣:

for arg in elem1 elem2 ... elemN
do### 語句
done

在每次循環(huán)的過程中,arg 依次被賦值為從 elem1 到 elemN。這些值還可以是通配符或者大括號擴展。

當(dāng)然,我們還可以把 for 循環(huán)寫在一行,但這要求 do 之前要有一個分號,就像下面這樣:

for i in {1..5}; do echo $i; done

還有,如果你覺得 for…in…do 對你來說有點奇怪,那么你也可以像 C 語言那樣使用 for,比如:

for (( i = 0; i < 10; i++ )); doecho $i
done

當(dāng)我們想對一個目錄下的所有文件做同樣的操作時,for 就很方便了。舉個例子,如果我們想把所有的.bash 文件移動到 script 文件夾中,并給它們可執(zhí)行權(quán)限,我們的腳本可以這樣寫:

💻 “示例源碼”:

DIR=/home/zp
for FILE in ${DIR}/*.sh; domv "$FILE" "${DIR}/scripts"
done
# 將 /home/zp 目錄下所有 sh 文件拷貝到 /home/zp/scripts
while 循環(huán)

while 循環(huán)檢測一個條件,只要這個條件為 ,就執(zhí)行一段命令。被檢測的條件跟 if…then 中使用的基元并無二異。因此一個 while 循環(huán)看起來會是這樣:

while [[ condition ]]
do### 語句
done

跟 for 循環(huán)一樣,如果我們把 do 和被檢測的條件寫到一行,那么必須要在 do 之前加一個分號。

💻 “示例源碼”:

### 0到9之間每個數(shù)的平方
x=0
while [[ ${x} -lt 10 ]]; doecho $((x * x))x=$((x + 1))
done
#  Output:
#  0
#  1
#  4
#  9
#  16
#  25
#  36
#  49
#  64
#  81
until 循環(huán)

until 循環(huán)跟 while 循環(huán)正好相反。它跟 while 一樣也需要檢測一個測試條件,但不同的是,只要該條件為 假 就一直執(zhí)行循環(huán):

💻 “示例源碼”:

x=0
until [[ ${x} -ge 5 ]]; doecho ${x}x=`expr ${x} + 1`
done
#  Output:
#  0
#  1
#  2
#  3
#  4
select 循環(huán)

select 循環(huán)幫助我們組織一個用戶菜單。它的語法幾乎跟 for 循環(huán)一致:

select answer in elem1 elem2 ... elemN
do### 語句
done

select 會打印 elem1…elemN 以及它們的序列號到屏幕上,之后會提示用戶輸入。通??吹降氖?$?(PS3 變量)。用戶的選擇結(jié)果會被保存到 answer 中。如果 answer 是一個在 1…N 之間的數(shù)字,那么語句會被執(zhí)行,緊接著會進行下一次迭代 —— 如果不想這樣的話我們可以使用 break 語句。

💻 “示例源碼”:

#!/usr/bin/env bashPS3="Choose the package manager: "
select ITEM in bower npm gem pip
do
echo -n "Enter the package name: " && read PACKAGE
case ${ITEM} inbower) bower install ${PACKAGE} ;;npm) npm install ${PACKAGE} ;;gem) gem install ${PACKAGE} ;;pip) pip install ${PACKAGE} ;;
esac
break # 避免無限循環(huán)
done

這個例子,先詢問用戶他想使用什么包管理器。接著,又詢問了想安裝什么包,最后執(zhí)行安裝操作。

運行這個腳本,會得到如下輸出:

$ ./my_script
1) bower
2) npm
3) gem
4) pip
Choose the package manager: 2
Enter the package name: gitbook-cli
break 和 continue

如果想提前結(jié)束一個循環(huán)或跳過某次循環(huán)執(zhí)行,可以使用 shell 的 break 和 continue 語句來實現(xiàn)。它們可以在任何循環(huán)中使用。

break 語句用來提前結(jié)束當(dāng)前循環(huán)。

continue 語句用來跳過某次迭代。

💻 “示例源碼”:

# 查找 10 以內(nèi)第一個能整除 2 和 3 的正整數(shù)
i=1
while [[ ${i} -lt 10 ]]; doif [[ $((i % 3)) -eq 0 ]] && [[ $((i % 2)) -eq 0 ]]; thenecho ${i}break;fii=`expr ${i} + 1`
done
# Output: 6

💻 “示例源碼”:

# 打印10以內(nèi)的奇數(shù)
for (( i = 0; i < 10; i ++ )); doif [[ $((i % 2)) -eq 0 ]]; thencontinue;fiecho ${i}
done
#  Output:
#  1
#  3
#  5
#  7
#  9

函數(shù)

bash 函數(shù)定義語法如下:

[ function ] funname [()] {action;[return int;]
}

💡 說明:
函數(shù)定義時,function 關(guān)鍵字可有可無。
函數(shù)返回值 - return 返回函數(shù)返回值,返回值類型只能為整數(shù)(0-255)。如果不加 return 語句,shell 默認將以最后一條命令的運行結(jié)果,作為函數(shù)返回值。
函數(shù)返回值在調(diào)用該函數(shù)后通過 $? 來獲得。
所有函數(shù)在使用前必須定義。這意味著必須將函數(shù)放在腳本開始部分,直至 shell 解釋器首次發(fā)現(xiàn)它時,才可以使用。調(diào)用函數(shù)僅使用其函數(shù)名即可。

💻 “示例源碼”:

#!/usr/bin/env bashcalc(){PS3="choose the oper: "select oper in + - \* / # 生成操作符選擇菜單doecho -n "enter first num: " && read x # 讀取輸入?yún)?shù)echo -n "enter second num: " && read y # 讀取輸入?yún)?shù)execcase ${oper} in"+")return $((${x} + ${y}));;"-")return $((${x} - ${y}));;"*")return $((${x} * ${y}));;"/")return $((${x} / ${y}));;*)echo "${oper} is not support!"return 0;;esacbreakdone
}
calc
echo "the result is: $?" # $? 獲取 calc 函數(shù)返回值

執(zhí)行結(jié)果:

$ ./function-demo.sh
1) +
2) -
3) *
4) /
choose the oper: 3
enter first num: 10
enter second num: 10
the result is: 100

位置參數(shù)

位置參數(shù)是在調(diào)用一個函數(shù)并傳給它參數(shù)時創(chuàng)建的變量。

位置參數(shù)變量表:

變量描述
$0腳本名稱
$1 … $9第 1 個到第 9 個參數(shù)列表
${10} … ${N}第 10 個到 N 個參數(shù)列表(N 是一個正整數(shù))
$*$@除了 $0 外的所有位置參數(shù)
$#不包括 $0 在內(nèi)的位置參數(shù)的個數(shù)
$FUNCNAME函數(shù)名稱(僅在函數(shù)內(nèi)部有值)

💻 “示例源碼”:

#!/usr/bin/env bashx=0
if [[ -n $1 ]]; thenecho "第一個參數(shù)為:$1"x=$1
elseecho "第一個參數(shù)為空"
fiy=0
if [[ -n $2 ]]; thenecho "第二個參數(shù)為:$2"y=$2
elseecho "第二個參數(shù)為空"
fiparamsFunction(){echo "函數(shù)第一個入?yún)?#xff1a;$1"echo "函數(shù)第二個入?yún)?#xff1a;$2"
}
paramsFunction ${x} ${y}

執(zhí)行結(jié)果:

$ ./function-demo2.sh
第一個參數(shù)為空
第二個參數(shù)為空
函數(shù)第一個入?yún)?#xff1a;0
函數(shù)第二個入?yún)?#xff1a;0$ ./function-demo2.sh 10 20
第一個參數(shù)為:10
第二個參數(shù)為:20
函數(shù)第一個入?yún)?#xff1a;10
函數(shù)第二個入?yún)?#xff1a;20

執(zhí)行 ./variable-demo4.sh hello world ,然后在腳本中通過 $1、$2 … 讀取第 1 個參數(shù)、第 2 個參數(shù)。。。

函數(shù)處理參數(shù)

另外,還有幾個特殊字符用來處理參數(shù):

參數(shù)處理說明
$#返回參數(shù)個數(shù)
$*返回所有參數(shù)
$$腳本運行的當(dāng)前進程 ID 號
$!后臺運行的最后一個進程的 ID 號
$@返回所有參數(shù)(與 $* 相同)
$-返回 Shell 使用的當(dāng)前選項,與 set 命令功能相同。
$?函數(shù)返回值(或上一個命令的退出狀態(tài))

💻 “示例源碼”:

runner() {return 0
}name=zp
paramsFunction(){echo "函數(shù)第一個入?yún)?#xff1a;$1"echo "函數(shù)第二個入?yún)?#xff1a;$2"echo "傳遞到腳本的參數(shù)個數(shù):$#"echo "所有參數(shù):"printf "+ %s\n" "$*"echo "腳本運行的當(dāng)前進程 ID 號:$$"echo "后臺運行的最后一個進程的 ID 號:$!"echo "所有參數(shù):"printf "+ %s\n" "$@"echo "Shell 使用的當(dāng)前選項:$-"runnerecho "runner 函數(shù)的返回值:$?"
}
paramsFunction 1 "abc" "hello, \"zp\""
#  Output:
#  函數(shù)第一個入?yún)?#xff1a;1
#  函數(shù)第二個入?yún)?#xff1a;abc
#  傳遞到腳本的參數(shù)個數(shù):3
#  所有參數(shù):
#  + 1 abc hello, "zp"
#  腳本運行的當(dāng)前進程 ID 號:26400
#  后臺運行的最后一個進程的 ID 號:
#  所有參數(shù):
#  + 1
#  + abc
#  + hello, "zp"
#  Shell 使用的當(dāng)前選項:hB
#  runner 函數(shù)的返回值:0

Shell 擴展

擴展 發(fā)生在一行命令被分成一個個的 記號(tokens) 之后。換言之,擴展是一種執(zhí)行數(shù)學(xué)運算的機制,還可以用來保存命令的執(zhí)行結(jié)果,等等。

感興趣的話可以閱讀關(guān)于 shell 擴展的更多細節(jié)。

大括號擴展

大括號擴展讓生成任意的字符串成為可能。它跟 文件名擴展 很類似,舉個例子:

echo beg{i,a,u}n ### begin began begun

大括號擴展還可以用來創(chuàng)建一個可被循環(huán)迭代的區(qū)間。

echo {0..5} ### 0 1 2 3 4 5
echo {00..8..2} ### 00 02 04 06 08

命令置換

命令置換允許我們對一個命令求值,并將其值置換到另一個命令或者變量賦值表達式中。當(dāng)一個命令被``或 $()包圍時,命令置換將會執(zhí)行。舉個例子:

now=`date +%T`
### or
now=$(date +%T)echo $now ### 19:08:26

算數(shù)擴展

在 bash 中,執(zhí)行算數(shù)運算是非常方便的。算數(shù)表達式必須包在 $(( ))中。算數(shù)擴展的格式為:

result=$(( ((10 + 5*3) - 7) / 2 ))
echo $result ### 9

在算數(shù)表達式中,使用變量無需帶上 $ 前綴:

x=4
y=7
echo $(( x + y ))     ### 11
echo $(( ++x + y++ )) ### 12
echo $(( x + y ))     ### 13

單引號和雙引號

單引號和雙引號之間有很重要的區(qū)別。在雙引號中,變量引用或者命令置換是會被展開的。在單引號中是不會的。舉個例子:

echo "Your home: $HOME" ### Your home: /Users/<username>
echo 'Your home: $HOME' ### Your home: $HOME

當(dāng)局部變量和環(huán)境變量包含空格時,它們在引號中的擴展要格外注意。隨便舉個例子,假如我們用 echo 來輸出用戶的輸入:

INPUT="A string  with   strange    whitespace."
echo $INPUT   ### A string with strange whitespace.
echo "$INPUT" ### A string  with   strange    whitespace.

調(diào)用第一個 echo 時給了它 5 個單獨的參數(shù) —— $INPUT 被分成了單獨的詞,echo 在每個詞之間打印了一個空格。第二種情況,調(diào)用 echo 時只給了它一個參數(shù)(整個 $INPUT 的值,包括其中的空格)。

來看一個更嚴肅的例子:

FILE="Favorite Things.txt"
cat $FILE   ### 嘗試輸出兩個文件: `Favorite` 和 `Things.txt`
cat "$FILE" ### 輸出一個文件: `Favorite Things.txt`

盡管這個問題可以通過把 FILE 重命名成 Favorite-Things.txt 來解決,但是,假如這個值來自某個環(huán)境變量,來自一個位置參數(shù),或者來自其它命令(find, cat, 等等)呢。因此,如果輸入 可能 包含空格,務(wù)必要用引號把表達式包起來。

流和重定向

Bash 有很強大的工具來處理程序之間的協(xié)同工作。使用流,我們能將一個程序的輸出發(fā)送到另一個程序或文件,因此,我們能方便地記錄日志或做一些其它我們想做的事。

管道給了我們創(chuàng)建傳送帶的機會,控制程序的執(zhí)行成為可能。

學(xué)習(xí)如何使用這些強大的、高級的工具是非常非常重要的。

輸入、輸出流

Bash 接收輸入,并以字符序列或 字符流 的形式產(chǎn)生輸出。這些流能被重定向到文件或另一個流中。

有三個文件描述符:

代碼描述符描述
0stdin標(biāo)準輸入
1stdout標(biāo)準輸出
2stderr標(biāo)準錯誤輸出

重定向

重定向讓我們可以控制一個命令的輸入來自哪里,輸出結(jié)果到什么地方。這些運算符在控制流的重定向時會被用到:

OperatorDescription
>重定向輸出
&>重定向輸出和錯誤輸出
&>>以附加的形式重定向輸出和錯誤輸出
<重定向輸入
<<Here 文檔語法
<<<Here 字符串

以下是一些使用重定向的例子:

### ls的結(jié)果將會被寫到list.txt中
ls -l > list.txt### 將輸出附加到list.txt中
ls -a >> list.txt### 所有的錯誤信息會被寫到errors.txt中
grep da * 2> errors.txt### 從errors.txt中讀取輸入
less < errors.txt

/dev/null 文件

如果希望執(zhí)行某個命令,但又不希望在屏幕上顯示輸出結(jié)果,那么可以將輸出重定向到 /dev/null:

$ command > /dev/null

/dev/null 是一個特殊的文件,寫入到它的內(nèi)容都會被丟棄;如果嘗試從該文件讀取內(nèi)容,那么什么也讀不到。但是 /dev/null 文件非常有用,將命令的輸出重定向到它,會起到”禁止輸出”的效果。

如果希望屏蔽 stdout 和 stderr,可以這樣寫:

$ command > /dev/null 2>&1

Debug

shell 提供了用于 debug 腳本的工具。

如果想采用 debug 模式運行某腳本,可以在其 shebang 中使用一個特殊的選項:

#!/bin/bash options

options 是一些可以改變 shell 行為的選項。下表是一些可能對你有用的選項:

ShortNameDescription
-fnoglob禁止文件名展開(globbing)
-iinteractive讓腳本以交互模式運行
-nnoexec讀取命令,但不執(zhí)行(語法檢查)
-t執(zhí)行完第一條命令后退出
-vverbose在執(zhí)行每條命令前,向 stderr 輸出該命令
-xxtrace在執(zhí)行每條命令前,向 stderr 輸出該命令以及該命令的擴展參數(shù)

舉個例子,如果我們在腳本中指定了 -x 例如:

#!/bin/bash -xfor (( i = 0; i < 3; i++ )); doecho $i
done

這會向 stdout 打印出變量的值和一些其它有用的信息:

$ ./my_script
+ (( i = 0 ))
+ (( i < 3 ))
+ echo 0
0
+ (( i++  ))
+ (( i < 3 ))
+ echo 1
1
+ (( i++  ))
+ (( i < 3 ))
+ echo 2
2
+ (( i++  ))
+ (( i < 3 ))

有時我們值需要 debug 腳本的一部分。這種情況下,使用 set 命令會很方便。這個命令可以啟用或禁用選項。使用-啟用選項,+禁用選項:

💻 “示例源碼”:

# 開啟 debug
set -x
for (( i = 0; i < 3; i++ )); doprintf ${i}
done
# 關(guān)閉 debug
set +x
#  Output:
#  + (( i = 0 ))
#  + (( i < 3 ))
#  + printf 0
#  0+ (( i++  ))
#  + (( i < 3 ))
#  + printf 1
#  1+ (( i++  ))
#  + (( i < 3 ))
#  + printf 2
#  2+ (( i++  ))
#  + (( i < 3 ))
#  + set +xfor i in {1..5}; do printf ${i}; done
printf "\n"
#  Output: 12345

往期精彩文章

Oracle 一鍵巡檢自動生成 Word 報告
Oracle 一鍵安裝合集
Oracle一鍵安裝腳本的 21 個疑問與解答
Oracle一鍵巡檢腳本的 21 個疑問與解答
全網(wǎng)首發(fā):Oracle 23ai 一鍵安裝腳本(非 RPM)
Oracle 19C 最新 RU 補丁 19.24 ,一鍵安裝!
Oracle Linux 7.9 一鍵安裝 Oracle 19C
RedHat 9.4(aarch64) 一鍵安裝 Oracle 19C
openEuler 22.03 LTS SP4 一鍵安裝 Oracle 19C RAC
RHEL 7.9 一鍵安裝 Oracle 19C 19.23 RAC
Oracle DataGuard GAP 修復(fù)手冊
優(yōu)化 Oracle:最佳實踐與開發(fā)規(guī)范
DBA 必備:Linux 軟件源配置全攻略
Linux 一鍵配置時鐘同步全攻略


感謝您的閱讀,這里是 Lucifer三思而后行,歡迎點贊+關(guān)注,我會持續(xù)分享數(shù)據(jù)庫知識、運維技巧。

http://www.risenshineclean.com/news/59864.html

相關(guān)文章:

  • 重慶網(wǎng)站建設(shè) cqhtwl臨沂百度代理公司有幾個
  • 外貿(mào)網(wǎng)站做紙尿褲怎么樣wordpress自助建站
  • 長春網(wǎng)站制作可選源晟4推廣產(chǎn)品最好的方式
  • 代運營公司排名前十西安關(guān)鍵詞優(yōu)化排名
  • 中國空間站太小了公司培訓(xùn)
  • 集團網(wǎng)站 源碼網(wǎng)站設(shè)計公司排名
  • 廣州海珠區(qū)繁華嗎排名seo公司哪家好
  • wordpress 插件 論壇常州seo排名收費
  • 建設(shè)手機網(wǎng)站的公司灰色seo推廣
  • 網(wǎng)站平臺建設(shè)的作用巨量算數(shù)數(shù)據(jù)分析
  • 安徽網(wǎng)站設(shè)計流程軟文發(fā)布平臺媒體
  • 找人做一個網(wǎng)站要多少錢百度推廣客戶端怎么登陸
  • 制作花燈百度刷排名優(yōu)化軟件
  • wap游戲縱橫四海優(yōu)化設(shè)計卷子答案
  • 做月季評分表的工程網(wǎng)站叫什么西安百度推廣開戶多少錢
  • 室內(nèi)設(shè)計軟件手機版semseo是什么意思
  • 中國住房和城鄉(xiāng)建設(shè)部網(wǎng)站安全seo優(yōu)化排名軟件
  • 鞋圖相冊網(wǎng)站怎么做seo網(wǎng)站優(yōu)化網(wǎng)站編輯招聘
  • 建設(shè)彩票網(wǎng)站犯法嗎seo網(wǎng)站排名優(yōu)化公司哪家好
  • 推廣引流文案鄭州網(wǎng)站優(yōu)化外包
  • 知名做漫畫網(wǎng)站百度官網(wǎng)進入
  • 南通市住房城鄉(xiāng)建設(shè)局網(wǎng)站百度服務(wù)中心人工24小時電話
  • 做網(wǎng)站公司漢獅團隊google play三件套
  • 知名網(wǎng)站建設(shè)多少錢排名優(yōu)化工具下載
  • 網(wǎng)頁的定義seo推廣軟件排行榜
  • 網(wǎng)站備案 身份證廣州seo成功案例
  • 福鼎建設(shè)局網(wǎng)站首頁最簡單的網(wǎng)頁制作
  • 網(wǎng)站怎么做微信登錄四川網(wǎng)站制作
  • 網(wǎng)站建設(shè)南京關(guān)鍵詞seo價格
  • 桃江縣建設(shè)局網(wǎng)站凱里seo排名優(yōu)化