SAKA'S BLOG

shell变量

1. 变量设置
1
2
3
4
<variable>=<value>  #为变量赋值
echo $<variable> #输出变量的值
echo ${<variable>} #输出变量的值,效果同上
unset variable #取消变量的值
  1. 变量与值之间以一个=连接
  2. 等号两边不能有空格
  3. 变量名称只能是英文字母与数字,且不能以数字开头
  4. 变量内容如果有空格可以使用双引号或者单引号将内容包裹起来。一般情况下,变量内容中含有变量的引用,也就是包含$<variable>,则用双引号包裹,一般字符则用单引号包裹。
  5. 可以使用转义字符“\”来使特殊符号变为一般符号。
  6. 假如变量内容中包含其他命令提供的信息,则需要使用以下两种形式:

    `\`

$(<command>)

  1. 若为变量增加内容时,可以使用$(<variable>)addition或者$<variable>addition形式。

例如:PATH="$PATH":/home/bin

  1. export关键字用来设置环境变量,可以传递给当前bash和子进程。
  2. 通常大写字母为系统默认变量,小写字母为自己设置的变量。例如PATH,HOME,SHELL等,均为系统变量。

下面写一个简单的例子来验证上面的语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
tmp="I am tmp"                      #*定义变量,=两边不能有空格,否则报错
echo "first type $tmp" #*"$<variable>"形式输出变量
echo "second type ${tmp}" #*"${<variable>}"另一种形式输出变量
echo 'third type ${tmp}' #*'$<variable>'不能输出变量
echo "with acutual '$' is \$tmp" #*用转义字符输出特殊字符
version=$(uname -r) #*$(command)方式获取函数的值
echo "first $version"
version=`pwd` #*`command`方式获取函数的值
echo "second $version"
unset version #*删除变量的值
echo "no version $version" #*不输出任何内容
tmp="${tmp} add new words" #*为tmp添加内容,注意$取变量的格式
echo $tmp #*输出添加后的内容
var="parent process var"
export var #*输出变量var到子线程
echo "parent pid=$$"

bash command echo \
"child pid=$$" \
&& command echo \
"child process var=$var" \
&& command echo \
"child process tmp=$tmp"

注释已经解释的很好了,查看输出内容:

1
2
3
4
5
6
7
8
9
first type I am tmp
second type I am tmp
third type ${tmp}
with acutual '$' is $tmp
first 17.4.0
second /Users/saka/Downloads/Markdown/shell命令
no version
I am tmp add new words
parent pid=19895
2. 变量的作用域

变量的作用域分为环境变量、全局变量、局部变量。

  1. 环境变量是系统中已经定义好的变量,输入env即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SHELL=/bin/zsh
TMPDIR=/var/folders/1x/gcpxck2s0jxbfs6qll8p0jlh0000gn/T/
Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.X4uBMH5DE9/Render
TERM_PROGRAM_VERSION=1.20.0
ZSH=/Users/saka/.oh-my-zsh
USER=saka
COMMAND_MODE=unix2003
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
PWD=/Users/saka/Downloads/Markdown/shell命令
LANG=zh_CN.UTF-8
XPC_FLAGS=0x0
XPC_SERVICE_NAME=0
var=parent process var
VSCODE_NODE_CACHED_DATA_DIR_18562=/Users/saka/Library/Application Support/Code/CachedData/c63189deaa8e620f650cc28792b8f5f3363f2c5b
SHLVL=30
HOME=/Users/saka
VSCODE_NLS_CONFIG={"locale":"zh-cn","availableLanguages":{"*":"zh-cn"}}
LESS=-R

这些变量都可以直接在shell脚本中获取。

  1. 全局变量
    shell脚本,包括shell脚本中的函数中定义的变量是global的,其作用域从被定义的地方开始,到shell结束或被显示删除的地方为止。
  2. 局部变量
    函数定义的变量可以被显示定义成local的,其作用域局限于函数内。但请注意,函数的参数是local的。如果变量同名,Shell函数定义的local变量会屏蔽脚本定义的global变量。

一个简单的例子说明:

1
2
3
4
5
6
7
8
9
10
11
12
echo "env variable SHELL=${SHELL}"          #*输出环境变量SEHLL的默认值
function showshell(){ #*定义一个函数
SHELL="custom shell" #*将SHELL设置为自己需要的变量
local var="local var" #*定义函数内的局部变量
echo "function SHELL=$SHELL" #*输出SHELL,已变为自定义变量
echo "local var=${var}" #*输出局部变量,有效
}
showshell #*执行函数showshell
echo "after showshell SHELL=${SHELL}" #*输出SHELL,函数外有效
echo "local var=${var}" #*输出函数内的局部变量,无效
unset SHELL
echo "after unset SHELL=${SHELL}" #*执行unset后,变量已无值,包括环境变量

查看输出结果:

1
2
3
4
5
6
env variable SHELL=/bin/zsh
function SHELL=custom shell
local var=local var
after showshell SHELL=custom shell
local var=
after unset SHELL=
3. 对变量的操作

首先来看一张总的表:

  • 变量的替换与删除
变量设置方式 说明
${变量#关键字} 若变量内容从头开始的数据符合“关键字”,则将符合的最短数据删除
$(变量##关键字) 若变量内容从头开始的数据符合“关键字”,则将符合的最长数据删除
${变量%关键字} 若变量内容从末端向前的数据符合“关键字”,则将符合的最短数据删除
${变量%%关键字} 若变量内容从末端向前的数据符合“关键字”,则将符合的最长数据删除
${变量/旧字符串/新字符串} 若变量内容符合“旧字符串”,则第一个旧字符串会被新字符串替换
${变量//旧字符串/新字符串} 若变量内容符合“旧字符串”,则全部的旧字符串会被新字符串替换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
path="abcdeaAbcedeA"
echo "字符*匹配任意个字符,下边是原有的值"
echo $path
echo "从开始位置匹配第一个'a',然后一直删除到第一个碰到的'de'"
echo ${path#a*de}
echo "从开始位置匹配到第一个'a',然后一直删除到最后一个碰到的'de'"
echo ${path##a*de}
echo "从末尾开始匹配到第一个'A',然后一直删除到向前寻找到的第一个'c'"
echo ${path%A*c}
echo "从末尾开始匹配到第一个'A',然后一直删除到向前寻找到的最后一个'c'"
echo ${path%%A*c}
echo "替换一个a为Z"
echo ${path/a/Z}
echo "替换所有的a为Z"
echo ${path//a/Z}

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
字符*匹配任意个字符,下边是原有的值
abcdeaAbcedeA
从开始位置匹配第一个'a',然后一直删除到第一个碰到的'de'
aAbcedeA
从开始位置匹配到第一个'a',然后一直删除到最后一个碰到的'de'
A
从末尾开始匹配到第一个'A',然后一直删除到向前寻找到的第一个'c'
abcdeaAbcedeA
从末尾开始匹配到第一个'A',然后一直删除到向前寻找到的最后一个'c'
abcdeaAbcedeA
替换一个a为Z
ZbcdeaAbcedeA
替换所有的a为Z
ZbcdeZAbcedeA
  • 变量的设置
设置方式 str没有设置 str=”” str有值
var=${str-expr} var=expr var= var=$str
var=${str:-expr} var=expr var=expr var=$str
var=${str+expr} var= var=expr var=expr
var=${str:+expr} var= var= var=expr
var=${str=expr} str=expr
var=expr
str不变
var=
str不变
var=$str
var=${str:=expr} str=expr
var=expr
str=expr
var=expr
str不变
var=$str
var=${str?expr} expr输出到stderr var= var=str
var=${str:?expr} expr输出到stderr expr输出到stderr var=str

这个比较简单,不写测试用例。主要说明一下’-‘和’:’:

假如-前边的变量未设置值,则取后边的变量假如前边的变量已经设置值,则输出前边的变量。
假如:-一同使用,则前边的变量未设置或者值为””,则用后边的值替换前边的值,否则不替换

4. 变量的声明
  • 通过用户输入设置变量的值

声明形式

1
2
3
4
5
6
read [-ptns] <variable>
参数:
-p : 后面接提示的内容
-t : 后面接等待的时间,单位为秒
-n : 后面接需要读取的字符个数
-s : 以无回显得方式读取数据,例如密码

编写一个简单的脚本测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
#/bin/zsh
echo "请根据下面的提示输入你想要设置的值"
read -p "var1= " var1
read -p "var2= " var2
read -p "你已经输入了所有的变量值,是否立即打印?y/n:" print
if [ ${print}x == yx ];then
echo "var1= $var1"
echo "var2= $var2"
elif [ ${print}x == nx ];then
echo "complete"
else
echo unknow command
fi

执行即可:

1
2
3
4
5
6
请根据下面的提示输入你想要设置的值
var1= 9
var2= 8
你已经输入了所有的变量值,是否立即打印?y/n:y
var1= 9
var2= 8
  • declare/typeset

定义形式

1
2
3
4
5
6
declare [-aixrp] variable
参数:
-a : 将变量定义为数组类型
-i : 将变量定义为整型
-x : 将变量输出为环变量
-r : 将变量设置为只读类型(readonly),相当于java中的常量

declare -x <variable>能将变量提升为环境变量,declare +x <varibale>能将变量取消为环境变量。

bash中的变量假如不是用声明方式,默认都是字符串。声明后可以进行简单的操作。一个简单的例子说明:

1
2
3
4
5
6
7
8
9
10
#bin/bash
sum_one=100+10 #*直接声明,是字符串格式
echo $sum_one #*输出100+10
declare -i sum #*声明为整型
sum=100+10 #*计算结果
echo $sum #*输出为110
declare -a array #*定义数组
array[1]="a" #*定义元素1
array[2]="b" #*定义元素2
echo ${array[*]} #*输出数组
1
2
3
100+10
110
a b