定义变量
定义变量时,变量名不需要加美元符号($),如:
variableName="value"
注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:
- 首个字符必须为字母(a-z,A-Z)。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用 bash 里的关键字(可用 help 命令查看保留关键字)。
Bash 没有数据类型的概念,所有的变量值都是字符串。
下面是一些自定义变量的例子。
# 不使用任何引号
$ myGender=man
# 使用单引号
$ myName='Wei Shi'
# 使用双引号
$ myUrl="http://test.com"
# 可以将一个数字赋值给变量(但是这个变量仍然是一个字符串变量)
$ myNum=100
三种定义方法
直接赋值就是使用一个等于号了,这在其他编程语言里也很常见,比如:
a=123
b=abc
c=‘123’
d=“hello world”
注意空格
需要注意的是等号左右不能有空格!!!比如如果出现a = 22
,执行该.sh时则会直接报错
无引号
b=abc
单引号
Bash 允许字符串放在单引号或双引号之中,加以引用。
单引号用于保留字符的字面含义,各种特殊字符在单引号里面,都会变为普通字符,比如星号(*
)、美元符号($
)、反斜杠(\
)等。
str='this is a string'
这意味着:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行,因为转义字符”\“也变成了普通字符),但可成对出现(即作为字符串拼接使用)。
# 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
$ a="sss"
$ str='this is a string $a'
$ echo $str
this is a string $a
# 单引号字串中不能出现单独一个的单引号(即使对单引号使用转义符后也不行)
$ str='this is a string\' for testing'
zsh: parse error near `for'
# 单引号字串中的单引号可以成对出现(来实现字符串拼接)
$ str='this is a string'' hahaha'
$ echo $str
this is a string hahaha
双引号
双引号比单引号宽松,可以保留大部分特殊字符的本来含义,但是三个字符除外:美元符号($
)、反引号(`` )和反斜杠(
`)。也就是说,这三个字符在双引号之中,会被 Bash 自动扩展。
# 双引号的引号之间可以使用变量,来进行字符串拼接
$ your_name="Wei"
$ str="Hello, I know you are $your_name"
$ echo $str
Hello, I know you are Wei
# 或者
$ str="Hello, I know you are "$your_name
$ echo $str
Hello, I know you are Wei
# 进行字符串拼接
$ str="I am $your_name, Hello"
$ echo $str
I am Wei, Hello
$ str="I am ${your_name}, Hello"
$ echo $str
I am Wei, Hello
# 双引号里可以出现双引号(通过使用转义字符)
$ str="I am \"Wei\""
$ echo $str
I am "Wei"
双引号的优点:
- 双引号的引号之间可以使用变量,来进行字符串拼接
- 双引号里可以出现双引号(通过使用转义字符)
从标准输入读取并为变量赋值
读取终端的输入给变量赋值,就是使用read命令。read和echo一样都是内嵌命令。直接看代码:
echo -n "Please Input your name:"
read name
echo "Hi,$name,welcome to uncle Jelly's cabin!"
或者可以使用read命令的 -p 选项来简化上述代码:
read -p "Please Input your name:" name
echo "$name,welcome to uncle jelly's cabin!"
变量类型
只读变量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
下面的例子尝试更改只读变量,结果报错:
#!/bin/bash
myUrl="http://test.com"
readonly myUrl
myUrl="http://test1.com"
运行脚本,结果如下:
/bin/sh: NAME: This variable is read only.
数值变量
数值变量赋值与运算
需要注意的是 Shell 默认赋值是字符串赋值,因此进行下面的操作:
$ myAge=20
$ myAgeAdd=$myAge+1
$ echo $myAgeAdd
29+1
使用 let
在 Bash 中,如果要将算术表达式的数值赋值给一个变量,可以使用 let 命令,如下所示:
$ let var=2+1
$ echo $var
3
# 自增
$ let var+=1
$ echo $let
4
使用 $[]
- 表示进行数值运算
$ x=1
$ echo $[$x+1]
2
# 自增
$ ((x++))
$ echo $x
3
使用 expr
expr命令为Linux中的命令,一般用于整数值计算,但也可用于字符串操作。
使用格式:
expr var1 operator var2
$ x=1
$ expr $x + 4
5
# b=expr $x + 4 是错误的
$ b=`expr $x + 4 `
$ echo $b
5
$ a=6
# 加法
$ expr $a + $b
11
# 减法
$ expr $a - $b
1
# 乘法
$ expr $a \* $b
30
$ val=`expr $a \* $b`
$ echo "a * b : $val"
a * b : 30
# 除法
$ expr $a / $b
1
# 求余
$ expr $a % $b
1
需要注意的是:
- 操作符和操作数之间一定要有空格间隔
- 操作数(即变量)前必须有$符
- 使用
expr
进行乘法运算时,要使用\*
, 即使用反斜杠\
进行转义 - 该命令会将计算结果打印到标准输出
- 仅支持整数运算(如果操作数不为整数,命令将会报错)
- 也可以直接使用数字的字面值
使用 $(())
$ b=5
# a=(($b+1)) 是错误的
$ a=$(($b+1))
$ echo $a
$ x=1
# 自增
$ ((x++))
$ echo $x
3
字符串变量
获取字符串长度
$ str="abcd"
$ echo ${#str}
4
提取子字符串
以下实例从字符串第 2 个字符开始截取 4 个字符:
$ string="swsmile is a great site"
$ echo ${string:1:4}
wsmi
从左边第几个字符开始一直到结束
$ string="swsmile is a great site"
$ echo ${string:1}
wsmile is a great site
查找子字符串
查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):
$ string="runoob is a great site"
$ echo "expr index $string io"
4
#
- 从左向右搜索指定字符(串),搜索到后向右取指定字符右侧的所有字符(不包括指定字符)
这种截取方式无法指定字符串长度,只能从指定字符(子字符串)截取到字符串末尾。Shell 可以截取指定字符(子字符串)右边的所有字符,也可以截取左边的所有字符。
使用#
号可以截取指定字符(或者子字符串)右边的所有字符,具体格式如下:
${string#*chars}
其中,string 表示要截取的字符,chars 是指定的字符(或者子字符串),*
是通配符的一种,表示任意长度的字符串。*chars
连起来使用的意思是:忽略左边的所有字符,直到遇见 chars(chars 不会被截取)。
$ url="https://swsmile.info/2020/08/22/%E3%80%90Microservices%E3%80%91service-mesh/"
$ echo ${url#*:}
//swsmile.info/2020/08/22/%E3%80%90Microservices%E3%80%91service-mesh/
如果不需要忽略 chars 左边的字符,那么也可以不写*
,例如:
$ url="https://swsmile.info/2020/08/22/%E3%80%90Microservices%E3%80%91service-mesh/"
$ echo ${url#http://}
swsmile.info/2020/08/22/%E3%80%90Microservices%E3%80%91service-mesh/
##
- 从右向左搜索指定字符(子字符串),搜索到后向右取指定字符(或者子字符串)右边的所有字符(不包括指定字符)
如果希望直到遇到最后一个指定字符(子字符串),才匹配结束,那么可以使用##
,具体格式为:
${string##*chars}
比如:
$ url="https://swsmile.info/2020/08/22/%E3%80%90Microservices%E3%80%91service-mesh/aa"
$ echo ${url#*/}
/swsmile.info/2020/08/22/%E3%80%90Microservices%E3%80%91service-mesh/aa
$ echo ${url##*/}
aa
%
- 从右向左搜索指定字符(子字符串),搜索到后取指定字符(或者子字符串)左边的所有字符(不包括指定字符)
${string%*chars}
比如:
$ url="https://swsmile.info/2020/08/22/%E3%80%90Microservices%E3%80%91service-mesh/aa"
$ echo ${url%*/}
/swsmile.info/2020/08/22/%E3%80%90Microservices%E3%80%91service-mesh/aa
$ echo ${url##*/}
aa
数组(array)
数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小(与 PHP 类似)。
与大部分编程语言类似,数组元素的下标由0开始。
Shell 数组用括号来表示,元素用"空格"符号分割开,语法格式如下:
array_name=(value1 value2 ... valuen)
声明
# To declare static Array
arr=(prakhar ankit 1 rishabh manish abhinav)
# or
NAME[0]="Zara"
NAME[1]="Qadir"
NAME[2]="Mahnaz"
NAME[3]="Ayan"
NAME[4]="Daisy"
# If you are using the bash shell, here is the syntax of array initialization −
array_name=(value1 ... valuen)
my_array=("a" "b" "c")
Access Array Values
After you have set any array variable, you access it as follows −
${array_name[index]}
Here array_name is the name of the array, and index is the index of the value to be accessed. Following is an example to understand the concept −
#!/bin/sh
NAME[0]="Zara"
NAME[1]="Qadir"
NAME[2]="Mahnaz"
NAME[3]="Ayan"
NAME[4]="Daisy"
echo "First Index: ${NAME[0]}"
echo "Second Index: ${NAME[1]}"
The above example will generate the following result −
For Loop
#!/bin/bash
array=("A" "B" "ElementC" "ElementE")
for element in "${array[@]}"
do
echo "$element"
done
echo
# get array's len
echo "Number of elements: ${#array[@]}"
# or
echo "Number of elements: ${#array[*]}"
echo
echo "${array[@]}"
Result:
A
B
ElementC
ElementE
Number of elements: 4
A B ElementC ElementE
总结
格式 | 说明 |
---|---|
${string: start :length} | 从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。 |
${string: start} | 从 string 字符串的左边第 start 个字符开始截取,直到最后。 |
${string: 0-start :length} | 从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。 |
${string: 0-start} | 从 string 字符串的右边第 start 个字符开始截取,直到最后。 |
${string#*chars} | 从 string 字符串第一次出现 *chars 的位置开始,取 *chars 右边的所有字符(不包括*chars)。 |
${string##*chars} | 从 string 字符串最后一次出现 *chars 的位置开始,取 *chars 右边的所有字符(不包括*chars)。 |
${string%*chars} | 从 string 字符串第一次出现 *chars 的位置开始,取 *chars 左边的所有字符(不包括*chars)。 |
${string%%*chars} | 从 string 字符串最后一次出现 *chars 的位置开始,取 *chars 左边的所有字符(不包括*chars)。 |
使用变量
使用一个定义过的变量,只要在变量名前面加美元符号($)即可,如:
$ your_name="wei"
$ echo $your_name
$ echo ${your_name}
变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:
for skill in Ada Coffe Action Java
do
echo "I am good at ${skill}Script"
done
如果不给 skill 变量加花括号,写成 echo “I am good at $skillScript”,解释器就会把 $skillScript 当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。
推荐给所有变量加上花括号,这是个好的编程习惯。
将命令的执行结果赋值给变量
$ var=`pwd`
$ echo $var
此时输出:
/Users/wei.shi/Downloads
或者也可以使用 $(...)
来实现同样的功能
$ var=$(pwd)
$ echo $var
变量操作
重新定义变量
已定义的变量,可以被重新定义,如:
$ myUrl="http://test.com"
$ echo ${myUrl}
$ myUrl="http://test1.com"
$ echo ${myUrl}
删除变量
使用 unset 命令可以删除变量。语法:
$ unset variable_name
变量被删除后不能再次使用;unset 命令不能删除只读变量。
举个例子:
#!/bin/sh
myUrl="http://test.com"
unset myUrl
echo $myUrl
上面的脚本没有任何输出。
变量类型
运行 shell 时,会同时存在三种变量:
1) 局部变量
局部变量在脚本或命令中定义,仅在当前 shell 实例中有效,其他 shell 启动的程序不能访问局部变量。
2) 环境变量
所有的程序,包括 shell 启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候 shell 脚本也可以定义环境变量。
3) shell 特殊变量(special parameters)
shell 特殊变量(special parameters)是由 shell 程序设置的特殊变量。shell 变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了 shell 的正常运行:
$$
:Shell本身的PID(ProcessID)$!
:Shell最后运行的后台Process的PID$?
:最后运行的命令的结束代码(返回值)$-
:使用Set命令设定的Flag一览$*
:传递到Shell的所有参数列表(每个参数之间用空格连接)$@
:传递到Shell的所有参数列表(每个参数之间用换行连接)$#
:传递到Shell的参数个数$0
:Shell本身的文件名$1~$n
:传递到Shell的各参数值。$1是第1参数、$2是第2参数…。
Example:
$ vim bash.sh
#!/bin/bash
#
printf "%s\n" "$$"
printf "%s\n" "$!"
printf "%s\n" "$?"
printf "%s\n" "$*"
printf "%s\n" "$@"
printf "%s\n" "$#"
printf "%s\n" "$0"
printf "%s\n" "$1"
printf "%s\n" "$2"
$ bash ./test.sh aaa bbb
78487 # $$:当前Shell的PID)
# $!:Shell最后运行的后台Process的PID
0 # $?:最后运行的命令的结束代码(返回值)
aaa bbb # $*:传递到Shell的所有参数列表(每个参数之间用空格连接)
aaa # $@:传递到Shell的所有参数列表(每个参数之间用换行连接)
bbb
2 # $#:传递到Shell的参数个数
./test.sh # $0:Shell本身的文件名
aaa # $1: 传递到Shell的第0个参数的值
bbb # $2: 传递到Shell的第2个参数的值
Reference
-
man bash
-
https://wiki.jikexueyuan.com/project/shell-tutorial/shell-variable.html
-
https://stackoverflow.com/questions/1886374/how-to-find-the-length-of-an-array-in-shell