1. 程式人生 > 其它 >bash 教程-4 shell 變數 算術表示式 [MD]

bash 教程-4 shell 變數 算術表示式 [MD]

博文地址

我的GitHub 我的部落格 我的微信 我的郵箱
baiqiantao baiqiantao bqt20094 [email protected]

目錄

目錄

Bash 教程

本文改編自

網道的 Bash 教程,主要為了精簡大量本人不感興趣的內容。

Bash 變數

Bash 變數分成環境變數和自定義變數兩類。

  • 環境變數是 Bash 環境自帶的變數,可以直接使用。通常是系統定義好的,也可以由使用者從父 Shell 傳入子 Shell。
  • 自定義變數是使用者在當前 Shell 裡面自己定義的變數,僅在當前 Shell 可用。
set     # 顯示所有變數(包括環境變數和自定義變數),以及所有的 Bash 函式

環境變數

很多環境變數很少發生變化,而且是隻讀的,可以視為常量。

由於環境變數的變數名全部都是大寫,所以傳統上,如果使用者要自己定義一個常量,也會使用全部大寫的變數名。

env           # 【printenv】,顯示所有環境變數
echo $PATH    # 【printenv PATH】,檢視單個環境變數的值
echo -e ${PATH//:/"\n"}  # 將環境變數 PATH 中的所有分隔符,由【:】替換成【\n】,並解釋為換行符

echo -e "$BASHPID \n$BASHOPTS \n$DISPLAY \n$EDITOR \n$HOME \n$HOST \n$IFS \n$LANG"
echo -e "$PS1 \n$PS2 \n$PWD \n$RANDOM \n$SHELL \n$SHELLOPTS \n$TERM \n$UID \n$USER"

常見的環境變數。

  • BASHPID:【104】Bash 程序的程序 ID
  • BASHOPTS:當前 Shell 的引數,可以用shopt命令修改
  • DISPLAY:圖形環境的顯示器名字,通常是:0,表示 X Server 的第一個顯示器
  • EDITOR:預設的文字編輯器
  • HOME:【/home/bqt】使用者的主目錄
  • HOST:當前主機的名稱。
  • IFS:詞與詞之間的分隔符,預設為空格
  • LANG:【C.UTF-8】字符集以及語言編碼,比如zh_CN.UTF-8
  • PATH:由冒號分開的目錄列表,當輸入可執行程式名後,會搜尋這個目錄列表
  • PS1:Shell 提示符
  • PS2:【>】輸入多行命令時,次要的 Shell 提示符
  • PWD:【/home/bqt】當前工作目錄
  • RANDOM:【19211】返回一個0到32767之間的隨機數
  • SHELL:【/bin/bash】Shell 的名字
  • SHELLOPTS:啟動當前 Shell 的set命令的引數
  • TERM:【xterm-256color】終端型別名,即終端模擬器所用的協議
  • UID:【1000】當前使用者的 ID 編號
  • USER:【bqt】當前使用者的使用者名稱

定義變數

  • 變數名的規則和 Java 等程式語言一樣
  • 變數名區分大小寫
  • Bash 沒有資料型別的概念,所有的變數值都是字串
  • 注意,變數名和等號之間不能有空格
var=value    # 變數名區分大小寫,變數值都是字串
b="b qt"     # 如果變數值包含空格,必須放在引號裡面
e=$(pwd)     # 【e=`pwd`】變數值可以是命令的執行結果
f=$((5*7))   # 變數值可以是數學運算的結果
foo=1;bar=2  # 同一行定義多個變數,必須使用分號分隔

for file in $(ls $(pwd)); do echo $file; done

讀取變數

  • 如果變數不存在,會輸出空字元,而不會報錯
  • 在變數名與其他字元連用的情況下,必須使用 花括號 包圍的格式:${var}
  • 如果變數的值本身也是變數,必須在變數前面加 感嘆號 才能讀取最終的值:${!var}
  • 變數值包含連續空格、製表符、換行符時,直接讀取時會被合併成一個空格;放在 雙引號 裡面能保持原來的格式
echo $100.00   # 【00.00】Bash 將【$1】解釋成了變數,該變數不存在,會輸出空字元
echo \$100.00  # 【$100.00】加反斜槓進行轉義

bqt=baiqiantao
echo $bqt2022    # 【(空)】Bash 將其整個 bqt2022 解釋為變數,而這個變數是不存在的
echo ${bqt}2022  # 【baiqiantao2022】在變數名與其他字元連用的情況下,必須使用花括號包圍

var=USER
echo $var     # 【USER】
echo ${!var}  # 【bqt】如果變數的值本身也是變數,必須使用【${!var}】讀取最終的值

a="1 2   3"
echo $a     # 【1 2 3】直接讀取時,Shell 會將連續空格合併成一個
echo "$a"   # 【1 2   3】放在雙引號裡面讀取時,能保持原來的格式

刪除變數

unset 命令用來刪除一個變數,這個命令等價於將變數設成空字串。

這個命令不是很有用,因為不存在的 Bash 變數一律等於空字串,所以即使用 unset 命令刪除了變數,還是可以讀取這個變數,值為空字串。

# 以下三種方式效果是一樣的
unset bqt
bqt=''
bqt=

特殊變數 & 傳遞引數

Bash 提供一些特殊變數。這些變數的值由 Shell 提供,使用者不能進行賦值。

  • $0:當前 Shell 的名稱(在命令列直接執行時),或者指令碼檔名(在指令碼中執行時)
  • $n:傳遞到指令碼的第 n 個引數的值,建議使用 ${n} 來獲取
  • $#:傳遞到指令碼的引數數量
  • $*:顯示所有向指令碼或函式傳遞的引數,與$@基本相同,區別見下文
  • $@:顯示所有向指令碼或函式傳遞的引數,與$*基本相同,區別見下文
  • $?:上一個命令的退出碼,返回 0 表示上一個命令執行成功;否則,表示上一個命令執行失敗
  • $$:當前 Shell 的程序 ID,常用來輔助命名臨時檔案
  • $-:當前 Shell 的啟動引數
  • $_:上一個命令的最後一個引數,不一定是使用者輸入的引數
  • $!:最近一個後臺執行的非同步命令的程序 ID,沒有的話返回空
# 呼叫格式【./test.sh 29 男】
chmod 777 test.sh
echo $0   #【./test.sh】指令碼檔名
echo $1   #【29】
echo $2   #【男】

echo $#   #【2】傳遞到指令碼的引數數量
echo $*   #【29 男】以一個字串顯示所有向指令碼或函式傳遞的引數
echo $@   #【29 男】

echo $?   #【0】上一個命令的退出碼
echo $$   #【14372】當前 Shell 的程序 ID
echo $-   #【hBH】當前 Shell 的啟動引數
echo $_   #【hBH】上一個命令的最後一個引數,不一定是使用者輸入的引數
echo $!   #【】最近一個後臺執行的非同步命令的程序 ID

$*$@ 的區別:在雙引號中,$* 的作用是將所有引數當做一個引數

# 【./test.sh 29 男 白乾濤】
for i in $@;   do echo -n $i-; done;  # 【29-男-白乾濤】
for i in $*;   do echo -n $i-; done;  # 【29-男-白乾濤】

for i in "$@"; do echo -n $i-; done;  # 【29-男-白乾濤】
for i in "$*"; do echo -n $i-; done;  # 【29 男 白乾濤】注意,這裡是將所有引數當做一個引數

for i in '$@'; do echo -n $i-; done;  # 【$@】
for i in '$*'; do echo -n $i-; done;  # 【$*】

變數未定義時的預設值

  • ${var:-word}:如果變數 var 存在且不為空,則返回它的值,否則返回 word
  • ${var:=word}:如果變數 var 存在且不為空,則返回它的值,否則將它設為 word,並且返回 word
  • ${var:+word}:如果變數 var 存在且不為空,則返回 word,否則返回空值,可用來測試變數是否存在
  • ${var:?info}:如果變數 var 存在且不為空,則返回它的值,否則中斷指令碼的執行,並列印 var: info
echo ${abc:-"變數未定義"}  # 【變數未定義】
echo ${abc:="baiqiantao"} # 【baiqiantao】
echo ${bqt:+"變數已定義"}  # 【變數已定義】
echo ${abc:?"變數未定義"}  # 【bash: abc: 變數未定義】變數未定義時就中斷執行,並返回給定的報錯資訊
echo ${abc:?}             # 【bash: abc: parameter null or not set】可以省略報錯資訊

上面四種語法如果用在指令碼中,變數名的部分可以用數字19,表示指令碼的引數。

宣告輸出變數 export

  • export 命令用來向子 Shell 輸出變數。
  • 使用者建立的變數僅可用於當前 Shell,使用 export 命令可以把變數傳遞給子 Shell
  • 通過 export 命令輸出的變數,對於子 Shell 來說就是環境變數
  • 子 Shell 如果修改繼承的變數,不會影響父 Shell
bqt=baiqiantao
export bqt       # 輸出變數 bqt,執行後,當前 Shell 及隨後新建的子 Shell,都可以讀取變數 bqt
export var=value # 給變數賦值並輸出

# 子 Shell 如果修改繼承的變數,不會影響父 Shell
bash             # 新建子 Shell
echo $bqt        # 讀取 $bqt
bqt=baz          # 修改繼承的變數
exit             # 退出子 Shell
echo $bqt        # 讀取 $bqt

宣告只讀變數 readonly

宣告只讀變數,等同於 declare -r,聲明後無法改變變數值,也不能 unset 變數

readonly 命令有三個引數

  • -f:宣告的變數為函式名
  • -p:打印出所有的只讀變數
  • -a:宣告的變數為陣列

宣告時執行算術式 let

使用 let 命令宣告變數時,可以直接執行算術表示式。

let a=1+2      # 使用 let 命令宣告變數時,可以直接執行算術表示式
let "b =1 +2"  # 引數表示式如果包含空格,需要使用引號
echo $a $b     # 【3 3】

let "v1 = 1" v2=v1++  # 可以同時對多個變數賦值,賦值表示式之間使用空格分隔
echo $v1,$v2          # 【2,1】,v2=v1++ 的意思是:先返回 v1 的值,然後 v1 再自增

宣告特殊變數 declare

declare 命令可以宣告一些特殊型別的變數。declare 命令如果用在函式中,宣告的變數只在函式內部有效,等同於 local 命令。

  • 宣告整數變數 -i:聲明後可以直接進行數學運算
  • 宣告只讀變數 -r:等同於 readonly 命令,聲明後無法改變變數值,也不能 unset 變數
  • 宣告大寫字母 -u:聲明後可以自動把變數值轉成大寫字母
  • 宣告小寫字母 -l:聲明後可以自動把變數值轉成小寫字母
  • 輸出變數資訊 -p:輸出已定義變數的值,未定義的變數會提示找不到;不帶引數時輸出所有變數的資訊
  • 輸出環境變數 -x:等同於 export 命令,可以將一個變數輸出為子 Shell 的環境變數
  • 輸出所有函式名 -F:不包含函式定義
  • 輸出所有函式定義 -f:包含函式定義
  • 宣告陣列變數 -a
# 宣告整數變數
declare -i a=2 b=5 # 宣告整數變數,聲明後可以直接進行數學運算
declare -i c=a*b # 只要一個變數宣告為整數,它的賦值就會自動解釋為整數運算,這裡 a、b 可不宣告為整數變數
echo $a*$b=$c    # 【2*5=10】
c=bqt; echo $c   # 【0(不確定的值)】變數宣告為整數以後,如果被改寫為字串,不會報錯,但會賦以不確定的值

# 宣告只讀變數
declare -r r=1   # 宣告只讀變數,等同於 readonly 命令,聲明後無法改變變數值,也不能 unset 變數
r=2              # 【bash: r: readonly variable】報錯,命令執行失敗
unset r          # 【bash: unset: r: cannot unset: readonly variable】

# 宣告大/小寫
declare -u u     # 宣告大寫字母,聲明後可以自動把變數值轉成大寫字母
u=bQt; echo $u   # 【BQT】
declare -l l     # 宣告小寫字母,聲明後可以自動把變數值轉成小寫字母
l=bQt; echo $l   # 【bqt】

# 輸出變數資訊
p=bqt
declare -p p     # 【declare -- p="bqt"】
declare -p pp    # 【bash: declare: pp: not found】
declare -p       # 輸出所有變數的資訊

# 其他
declare -x x     # 輸出環境變數,等同於【export x】,可以將一個變數輸出為子 Shell 的環境變數
declare -F       # 輸出當前環境的所有函式名,不包含函式定義
declare -f       # 輸出當前環境的所有函式,包括它的定義
declare          # 等同於【set】命令,輸出當前環境的所有變數以及函式

整數的算術表示式 ((...))

算術表示式

((foo = 5 +5))  # 算術表示式,可以進行整數的算術運算,會自動忽略內部的空格
echo $? $foo    # 【0 10】只要算術結果不是 0,命令就算執行成功
(( 3 - 3 ))
echo $?         # 【1】如果算術結果為 0,命令就算執行失敗

echo $((2 + 2)) # 【4】算術表示式不返回值,但可在前面加上 $ 讀取算術運算的結果
echo $[2+2]     # 【4】以前的語法,也可以做整數運算,不建議使用
echo $((1.5+1)) # 【syntax error】只能對整數進行運算,如果有小數會報錯

# 在 $((...)) 內部,逗號前後的兩個表示式都會執行,並返回後一個表示式的值
echo $((a=1+2, b=3*4))  # 【12】兩個表示式都會執行,並返回後一個表示式的值
echo $a $b              # 【3 12】

括號中的字串

n=2; m="k"; k=n
echo $(($n + n))    # 【4】圓括號中,變數名前面的 $ 可以省略
echo $(("n" + 1))   # 【3】圓括號中的字串會認為是一個變數名
echo $(("nn" + 1))  # 【1】如果不存在同名變數,會將其作為空值,而不會報錯
echo $((k + m + n)) # 【6】動態替換

數值的進位制

Bash 的數值預設都是十進位制,但是在算術表示式中,也可以使用其他進位制。

  • number:沒有任何特殊表示法的數字是十進位制數
  • 0number:八進位制數
  • 0xnumber:十六進位制數
  • base#numberbase進位制的數
echo $((0xff)) - $((2#11111111))  # 【255 - 255】

max=$(( (1<<63)-1 )); # 最大值
echo $max $((max+1))  # 【9223372036854775807 -9223372036854775808】

# 十進位制轉為其它進位制,需要使用到外部命令 bc 完成
echo "obase=2; $max" | bc  # 【111...111】一共有 64 個 1

算術運算

  • +-*/
  • %:餘數
  • ++:自增運算
  • --:自減運算
  • **:指數運算,只有這個和 Java 等程式語言不一樣
echo $((5 / 2)) - $((5 % 2)) - $((2 ** 3))  # 【2 - 1 - 8】
echo $(( (2+3)*4 )) -  $(( $((2+3)) * 4 ))  # 【20 - 20】可以巢狀

i=0; j=0
echo $((i++)) - $i  # 【0 - 1】作為字尾是先返回值,再進行自增運算
echo $((++j)) - $j  # 【1 - 1】作為字首是先進行自增運算,再返回值

位運算

  • <</>>:位的左/右移運算,所有位向左/右移動指定的位
  • &|^:位的與/或/異或運算,對兩個數字的所有位執行一個AND/OR/異或操作
  • ~:位的運算,對一個數字的所有位取反
echo $((4>>2)) - $((4<<2))              # 【1 - 16】
echo $((17&3)) - $((2#10001 & 2#00011)) # 【1 - 1】
echo $((17|3)) - $((2#10001 | 2#00011)) # 【19 - 19】
echo $((17^3)) - $((2#10001 ^ 2#00011)) # 【18 - 18】

min=$(( (1<<63) ));    # 最小值
max=$(( (1<<63)-1 ));  # 最大值
echo $((~-2)) $((~-1)) $((~min)) $((~1)) $((~2))  # 【1 0 -1 -2 -3】
echo $((min-1)) $((min-2)) $((min-3))  # 【-1 -2 -3】

邏輯運算

  • > < >= <= == !=
  • && || !:邏輯與或非
  • expr1?expr2:expr3:若表示式 expr1 的計算結果為非零值,則執行表示式 expr2,否則執行表示式 expr3
echo $((3 > 2))             # 【1】如果邏輯表示式為真,返回 1
echo $(( (3>2) && (4<=1) )) # 【0】如果邏輯表示式為假,返回 0
echo $(( 2<1 ? 8 : 6 ))     # 【6】注意,後面只能是表示式,而不是是 echo 等語句

賦值運算

  • parameter = value
  • += -= *= /= %= <<= >>= &= |= ^=
echo $((a=1+1))  # 【2】對變數 a 進行賦值,這個式子的返回值就是等號右邊的值
echo $a          # 【2】
echo $((a*=2))   # 【4】

echo $(( a>1 ? (a+=1) : (a-=1) ))   # 【5】在表示式內部賦值,需要放在圓括號中

expr 和 let 命令

  • expr 是一款表示式計算工具,使用它也能完成以上所有 整數運算,但是運算子並不完全一樣
  • let 命令用於將算術運算的結果,賦予一個變數。
a=3
expr 3 + 2   # 【5】運算子前後必須至少有一個空格,此表示式有返回值
expr $a + 2  # 【5】支援變數替換
expr 3.5 + 2 # 【expr: non-integer argument】也不支援非整數的運算

let x=2+3    # 表示式【x=2+3】裡面不能有空格,否則會報錯
echo $x      # 【5】

2022-1-15

本文來自部落格園,作者:白乾濤,轉載請註明原文連結:https://www.cnblogs.com/baiqiantao/p/15806604.html