-
Notifications
You must be signed in to change notification settings - Fork 0
/
变量
285 lines (242 loc) · 10.2 KB
/
变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
1 shell变量基础
shell变量是一种很“弱”的变量,默认情况下,一个变量保存一个串,shell不关心这个串是什么含义。所以若要进行数学运算,
必须使用一些命令例如let、declare、expr、双括号等。shell变量可分为两类:局部变量和环境变量。局部变量只在创建它们的shell中可用。
而环境变量则可以在创建它们的shell及其派生出来的任意子进程中使用。有些变量是用户创建的,其他的则是专用shell变量。
变量名必须以字母或下划线字符开头。其余的字符可以是字母、数字(0~9)或下划线字符。任何其他的字符都标志着变量名的终止。
名字是大小写敏感的。给变量赋值时,等号周围不能有任何空白符。为了给变量赋空值,可以在等号后跟一个换行符。
用set命令可以查看所有的变量,unset var命令可以清除变量var,var相当于没有定义过。readonly var可以把var变为只读变量,
定义之后不能对var进行任何更改。对shell变量的引用方式很多,用这些方式可以方便的获取shell变量的值,变量值的长度,变量的一个字串,
变量被部分替换后的值等等。shell变量常见引用方式如下:
http://www.cnblogs.com/barrychiao/archive/2012/10/22/2733210.html
2 环境变量
环境变量的定义方法如下:
var=value
export var
shell在初始化的时候会在执行profile等初始化脚本,脚本中定义了一些环境变量,这些变量会在创建子进程时传递给子进程。
用env命令可以查看当前的环境变量。常用的系统环境变量如下:
_(下划线) 上一条命令的最后一个参数
BASH 展开为调用bash实例时使用的全路径名
CDPATH cd命令的搜索路径。它是以冒号分隔的目录列表,shell通过它来搜索cd命令指定的目标目录。例如.:~:/usr
EDITOR 内置编辑器emacs、gmacs或vi的路径名
ENV 每一个新的bash shell(包括脚本)启动时执行的环境文件。通常赋予这个变量的文件名是.bashrc。
EUID 展开为在shell启动时被初始化的当前用户的有效ID
GROUPS 当前用户所属的组
HISTFILE 指定保存命令行历史的文件。默认值是~/.bash_history。如果被复位,交互式shell退出时将不保存命令行历史
HISTSIZE 记录在命令行历史文件中的命令数。默认是500
HOME 主目录。未指定目录时,cd命令将转向该目录
IFS 内部字段分隔符,一般是空格符、制表符和换行符,用于由命令替换,循环结构中的表和读取的输入产生的词的字段划分
LANG 用来为没有以LC_开头的变量明确选取的种类确定locale类
OLDPWD 前一个工作目录
PATH 命令搜索路径。一个由冒号分隔的目录列表,shell用它来搜索命令,一个普通值为 /usr/gnu/bin:/usr/local/bin:/usr/ucb:/usr/bin
PPID 父进程的进程ID
PS1 主提示符串,默认值是$
PS2 次提示符串,默认值是>
PS3 与select命令一起使用的选择提示符串,默认值是#?
PS4 当开启追踪时使用的调试提示符串,默认值是+。追踪可以用set –x开启
PWD 当前工作目录。由cd设置
RANDOM 每次引用该变量,就产生一个随机整数。随机数序列可以通过给RANDOM赋值来初始化。如果RANDOM被复位,即使随后再设置,它也将失去特定的属性
REPLY 当没有给read提供参数时设置
SHELL 当调用shell时,它扫描环境变量以寻找该名字。shell给PATH、PS1、PS2、MAILCHECK和IFS设置默认值。HOME和MAIL由login(1)设置
SHELLOPTS 包含一列开启的shell选项,比如braceexpand、hashall、monitor等
UID 展开为当前用户的用户ID,在shell启动时初始化
3 数值变量
shell中默认把变量值当作字符串,例如:
age=22
age=${age}+1
echo ${age}
输出结果为22+1,而不是23,因为shell将其解释为字符串,而不是数学运算。
可以用let命令使其进行数学运算,例如:
let age=${age}+1
也可以用declare把变量定义为整型。例如:
declare -i age=22
这里就用 -i 选项把age定义为整型的了。此后每次运算,都把age的右值识别为算术表达式或数字。
4 数组
在shell中可以使用数组,例如:
array[0]=0
array[1]=1
array[2]=2
则array就是一个数组,也可以这样给数组初始化:
array=(0 1 2) // 元素之间以空格分隔
可以通过 ${array[$i]}来访问array中某个元素,${array[*]} 的返回值即数组的所有元素组成的串,${#array[*]} 的返回值即数组的元素个数,${array[*]:0:2} 返回第一个和第二个元素组成的串。0表示开始的位置,2表示要返回的元素个数,开始位置可以为0-2(0减去2)之类的,表示从倒数第二个元素开始。
下面写个稍微复杂点的例子:
复制代码
1 #!/bin/bash
2 for ((i=0; i<100; i++))
3 do
4 array[$i]=$i
5 done
6 for ((i=0; i<100; i++))
7 do
8 echo ${array[$i]}
9 done
复制代码
如果要使用二维数组甚至三维数组该怎么实现呢,那就需要用eval命令来模拟数组的功能了。
eval命令的作用是扫描命令两次再执行,如果不使用eval,只扫描一次,然后执行。看个例子:
root@suse:~$ name=Barry
root@suse:~$ $name=hello
Barry=hello: command not found
为什么第二句给Barry变量赋值会出错呢?从报错信息可以发现shell并没有识别这是个赋值语句,而是把Barry=hello当作一个命令来执行,当然会报错。为什么不能识别这是赋值语句呢?第一次扫描时,因为扫描到$符号,所以不能把这句当作赋值语句,赋值语句的左边总是一个变量名,而不应该是$开头的。所以第一次扫描仅仅识别了$name变量,并做了替换,而并没有认识到赋值语句。
如果使用eval $name=hello呢?
root@suse:~$ name=Barry
root@suse:~$ $name=hello
Barry=hello: command not found
root@suse:~$ eval $name=hello
root@suse:~$ echo $Barry
hello
可见使用了eval之后,对 $name=hello 第一次扫描替换了$name,没有识别赋值语句,第二次扫描识别是赋值语句,然后执行。现在大约可以想到怎样用eval实现二维数组了。
下面实现的二维数组每一行代表一个人的信息记录,包括姓名,年龄。
复制代码
1 for ((i=0; i<2; i++))
2 do
3 for ((j=0; j<2; j++))
4 do
5 read man$i$j
6 done
7 done
8 echo "next print:"
9 for ((i=0; i<2; i++))
10 do
11 for ((j=0; j<2; j++))
12 do
13 eval echo -n "\$man$i$j:"
14 done
15 printf "\n"
16 done
复制代码
5 特殊变量
$0:当前脚本的文件名
$num:num为从1开始的数字,$1是第一个参数,$2是第二个参数,${10}是第十个参数
$#:传入脚本的参数的个数
$*:所有的位置参数(作为单个字符串)
$@:所有的位置参数(每个都作为独立的字符串)。
$?:当前shell进程中,上一个命令的返回值,如果上一个命令成功执行则$?的值为0,否则为其他非零值,常用做if语句条件
$$:当前shell进程的pid
$!:后台运行的最后一个进程的pid
$-:显示shell使用的当前选项
$_:之前命令的最后一个参数
参数展开
whwu@master:~/script> cat para_ex.sh
#!/bin/bash
a="1" #将值储存在a中
for((i=1;i<=5;i++))
do
echo $a #显示变量a
sleep 10 #等待10秒钟
done
展开运算符
${ varname:-word} #如果varname存在且非null,则返回其值;否则,返回word
#! /bin/sh
tr -cs "[A-Z][a-z]" "\n" | # change the complement of letter to line break and delete continuous lines
tr "[A-Z]" "[a-z]"| # change upper to lower
sort | # sort accoeding to letters
uniq -c | # delete repeated words and show the number
sort -k1,1nr -k2 | # first sort according to number, large to small second sort in terms of letters
sed ${1:-25}q
whwu@master:~/script> cat para_ex.sh
#!/bin/bash
a="1"
for((i=1;i<=3;i++))
do
echo $a
echo ${b:-haha} #变量b没有定义,则显示haha
done
whwu@master:~/script> ./para_ex.sh
1
haha
1
haha
1
haha
${varname:=word} #如果varname存在且不是null,则返回它的值;否则,设置它为word,并返回其值,类似${varname:-word}
${varname:?message #如果varname存在且非null,则返回它的值;否则,显示varname:message,并退出当前的命令或脚本
whwu@master:~/script> cat para_ex.sh #变量存在且非null
#!/bin/bash
a="1"
b="2"
for((i=1;i<=3;i++))
do
echo $a
echo ${b:?"haha"}
done
whwu@master:~/script> ./para_ex.sh
1
2
1
2
1
2
whwu@master:~/script> cat para_ex.sh #变量不存在
#!/bin/bash
a="1"
for((i=1;i<=3;i++))
do
echo $a
echo ${b:?"haha"}
done
whwu@master:~/script> ./para_ex.sh
1
./para_ex.sh: line 7: b: haha
${varname:+word} #如果varname存在且非null,则返回word;否则,返回null
whwu@master:~/script> cat para_ex.sh #变量b不存在,返回null
#!/bin/bash
a="1"
for((i=1;i<=3;i++))
do
echo $a
echo ${b:+"haha"}
done
whwu@master:~/script> ./para_ex.sh
1
1
1
whwu@master:~/script> cat para_ex.sh #变量b存在,返回haha
#!/bin/bash
a="1"
b="2"
for((i=1;i<=3;i++))
do
echo $a
echo ${b:+"haha"}
done
whwu@master:~/script> ./para_ex.sh
1
haha
1
haha
1
haha
算术展开
whwu@master:~/script> echo $((3>2))
1
whwu@master:~/script> echo $((3 && 2))
1
whwu@master:~/script> echo $(( (3>2) || (4<=1) ))
1
whwu@master:~/script> echo $((i++)) $i
5 6
whwu@master:~/script> echo $((++i)) $i
7 7
退出状态
每一条命令,不管是内置的、shell函数,还是外部的,当它退出时,都会返回一个小的整数
值给引用它的程序,这就是程序的退出状态。0表示成功,也就是程序执行完成且未遭遇任何
问题。其他任何的退出状态都为失败。内置变量$?访问它。
whwu@master:~> ls 10nacl2.in
10nacl2.in
whwu@master:~> echo $?
0
whwu@master:~> ls 10nacl2.abc
ls: cannot access 10nacl2.abc: No such file or directory
whwu@master:~> echo $?
2
exit命令
语法: exit [exit-value] #从shell脚本返回一个退出状态给脚本的调用者。
whwu@master:~/script> cat exit.sh
#!/bin/bash
if [ "$1" -ne "2" ];then
echo "haha"
exit 12
fi
whwu@master:~/script> ./exit.sh 45
haha
whwu@master:~/script> echo $?
12