1. shell变量
Shell支持自定义变量。
1.1. 定义变量
定义变量时,变量名不加美元符号($),如:
注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:
- 首个字符必须为字母(a-z,A-Z)。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
1.2. 使用变量
使用一个定义过的变量,只要在变量名前面加美元符号($)即可,如:
1
2
3
|
your_name="mozhiyan"
echo $your_name
echo ${your_name}
|
变量名外面的花括号是可选的,加不加都行,,比如下面这种情况:
1
2
3
4
|
for skill in Ada Coffe Action Java
do
echo "I am good at ${skill}Script"
done
|
如果不给skill变量加花括号,写成echo “I am good at $skillScript”,解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。推荐给所有变量加上花括号,这是个好的编程习惯。
1.3. 重新定义变量
已定义的变量,可以被重新定义,如:
1
2
3
4
5
|
myUrl="http://see.xidian.edu.cn/cpp/linux/"
echo ${myUrl}
myUrl="http://see.xidian.edu.cn/cpp/shell/"
echo ${myUrl}
|
这样写是合法的,但注意,第二次赋值的时候不能写 $myUrl=“
http://see.xidian.edu.cn/cpp/shell/"
, 使用变量的时候才加美元符($)。
1.4. 只读变量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
下面的例子尝试更改只读变量,结果报错:
1
2
3
4
|
#!/bin/bash
myUrl="http://see.xidian.edu.cn/cpp/shell/"
readonly myUrl
myUrl="http://see.xidian.edu.cn/cpp/danpianji/"
|
运行脚本,结果如下:
1
|
/bin/sh: NAME: This variable is read only.
|
1.5. 删除变量
使用 unset 命令可以删除变量。语法:
变量被删除后不能再次使用;unset 命令不能删除只读变量。
举个例子:
1
2
3
4
5
|
#!/bin/sh
myUrl="http://see.xidian.edu.cn/cpp/u/xitong/"
unset myUrl
echo $myUrl
|
上面的脚本没有任何输出。
1.6. 变量类型
运行shell时,会同时存在三种变量:
1) 局部变量
局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
2) 环境变量
所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
3) shell变量
shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行。
2. shell的特殊变量
特殊变量列表
变量 |
含义 |
$0 |
当前脚本的文件名 |
$n |
传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。 |
$# |
传递给脚本或函数的参数个数。 |
$* |
传递给脚本或函数的所有参数。 |
$@ |
传递给脚本或函数的所有参数。被双引号(” “)包含时,与 $* 稍有不同,下面将会讲到。 |
$? |
上个命令的退出状态,或函数的返回值。 |
$$ |
当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。 |
2.1. 命令行参数
运行脚本时传递给脚本的参数称为命令行参数。命令行参数用\ $n 表示,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。
2.2. $* 和$@ 的区别
$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(” “)包含时,都以”$1" “$2” … “$n” 的形式输出所有参数。
但是当它们被双引号(" “)包含时,
2.3. 退出状态
$? 可以获取上一个命令的退出状态。所谓退出状态,就是上一个命令执行后的返回结果。
退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1。
不过,也有一些命令返回其他值,表示不同类型的错误。$? 也可以表示函数的返回值。
3. 转义字符
如果表达式中包含特殊字符,Shell 将会进行替换。例如,在双引号中使用变量就是一种替换,转义字符也是一种替换。
1
|
echo -e "Value of a is $a \n"
|
-e 表示对转义字符进行替换
下面的转义字符都可以用在 echo 中:
转义字符 |
含义 |
\ |
反斜杠 |
\a |
警报,响铃 |
\b |
退格(删除键) |
\f |
换页(FF),将当前位置移到下页开头 |
\n |
换行 |
\r |
回车 |
\t |
水平制表符(tab键) |
\v |
垂直制表符 |
可以使用 echo 命令的 -E 选项禁止转义,默认也是不转义的;使用 -n 选项可以禁止插入换行符。
4. 变量替换
4.1. 命令替换
命令替换是指Shell可以先执行命令,将输出结果暂时保存,在适当的地方输出。
命令替换的语法:
注意是反引号,不是单引号,这个键位于 Esc 键下方。
1
2
|
DATE=`date`
echo "Date is $DATE"
|
4.2. 变量替换
变量替换可以根据变量的状态(是否为空、是否定义等)来改变它的值
可以使用的变量替换形式:
形式 |
说明 |
${var} |
变量本来的值 |
${var:-word} |
如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值。 |
${var:=word} |
如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。 |
${var:?message} |
如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。 若此替换出现在Shell脚本中,那么脚本将停止运行。 |
${var:+word} |
如果变量 var 被定义,那么返回 word,但不改变 var 的值。 |
${var# 匹配规则} |
从开头进行匹配,将符合最短的数据删除 |
${var ## 匹配规则} |
从开头匹配,将符合的最长数据删除 |
${var % 匹配规则} |
尾部匹配,最短匹配删除 |
${var /olds/news} |
第一个旧的字符替换为新的字符串 |
${var//olds/news} |
将全部的 olds 替换为 news |
作用:用来检测变量是否为空,并提示相关信息。
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
|
lyr@DESKTOP-FSVN6C0:~$ i="i love you,do you love?"
lyr@DESKTOP-FSVN6C0:~$ a=${i#*love}
lyr@DESKTOP-FSVN6C0:~$ echo $a
you,do you love?
lyr@DESKTOP-FSVN6C0:~$ i="i love your, your monther
> "
lyr@DESKTOP-FSVN6C0:~$ a=${i##*love} && echo $a
your, your monther
# 这里 匹配到最后的 love,然后把前面的都删除了
lyr@DESKTOP-FSVN6C0:~$
lyr@DESKTOP-FSVN6C0:~$ a=${i%%*love} && echo $a
i love your, your monther
lyr@DESKTOP-FSVN6C0:~$ a=${i%%love*} && echo $a
i
# % 将 * 放入后面
# 替换 字符串
lyr@DESKTOP-FSVN6C0:~$ i="i love your monther,hiahia"
lyr@DESKTOP-FSVN6C0:~$ a=${i/monther/friend} && echo $a
i love your friend,hiahia
echo ${PATH/bin/BIN}
# 将 bin单词 替换为 BIN , 太长了,就截取一部分了
/usr/local/sBIN:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/d/Program Files/Eclipse Foundation/jdk-11.0.12.7-hotspot/bin:/mnt/c/Program Files (x86)/Common Files/Intel/Shared Libraries/redist/intel64/compiler:/mnt/c/Program Files (x86)/Common Files/Oracle/Java/javapath:/mnt/c/Program Files/Intel/iCLS Client/:/mnt/c/Windows/system32:/mnt/c/Windows:/mnt/c/Windows/System32/Wbem:/mnt/c/Windows/System32/WindowsPowerShell/v1.0/:/mnt/c/Program Files (x86)/Intel/Intel(R) Management Engine Components/DAL:/mnt/c/Program Files/Intel/Intel(R) Management Engine Components/DAL:/mnt/c/Program Files (x86)/Intel/Intel
|
变量测试
参考:
变量的作用域
- 不做特殊声明 ,shell中的变量都是全局变量
- tips: 大型脚本程序中函数 中慎用全局变量
1
2
3
4
5
6
|
function test
{
local s=88
echo $s
}
|
有类型变量
有类型变量声明
- declare -r # 声明为只读变量
- declare -i # 整形,int
- declare -f # 定义为函数和内容
- declare -F # 在脚本定义的函数
- declare -x # 声明为环境变量
-r 可读变量
1
2
3
4
5
6
7
|
lyr@DESKTOP-FSVN6C0:~$ num=10
lyr@DESKTOP-FSVN6C0:~$ num=20 && echo $num
20
lyr@DESKTOP-FSVN6C0:~$ declare -r num
lyr@DESKTOP-FSVN6C0:~$ num=666 && echo $num
-bash: num:只读变量
# 用 declare直接禁止 修改变量
|
-i 整形变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
lyr@DESKTOP-FSVN6C0:~$ var2=$num+666
lyr@DESKTOP-FSVN6C0:~$ echo $var2
20+666
lyr@DESKTOP-FSVN6C0:~$ declare -i var2
lyr@DESKTOP-FSVN6C0:~$ echo $var2
20+666
lyr@DESKTOP-FSVN6C0:~$ var2=$var2+1
lyr@DESKTOP-FSVN6C0:~$ echo $var2
687
# 直接整数运算了
lyr@DESKTOP-FSVN6C0:~$ expr $var2 + 44
731
lyr@DESKTOP-FSVN6C0:~$ s=`expr $var2 + 44`
lyr@DESKTOP-FSVN6C0:~$ s=`expr $var2 + 44` && echo $s
731
|
显示脚本定义的函数
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
|
lyr@DESKTOP-FSVN6C0:~$ declare -F
# 下面是显示的内容
declare -f __expand_tilde_by_ref
declare -f __get_cword_at_cursor_by_ref
declare -f __git_eread
declare -f __git_ps1
declare -f __git_ps1_colorize_gitstring
declare -f __git_ps1_show_upstream
declare -f __git_sequencer_status
declare -f __load_completion
declare -f __ltrim_colon_completions
declare -f __parse_options
declare -f __reassemble_comp_words_by_ref
declare -f _allowed_groups
declare -f _allowed_users
declare -f _apport-bug
declare -f _apport-cli
declare -f _apport-collect
declare -f _apport-unpack
declare -f _apport_parameterless
declare -f _apport_symptoms
declare -f _available_interfaces
declare -f _cd
declare -f _cd_devices
declare -f _chmod
declare -f _command
declare -f _command_offset
declare -f _complete_as_root
declare -f _completion_loader
declare -f _configured_interfaces
declare -f _count_args
declare -f _dvd_devices
declare -f _expand
declare -f _filedir
declare -f _filedir_xspec
declare -f _fstypes
declare -f _get_comp_words_by_ref
declare -f _get_cword
declare -f _get_first_arg
declare -f _get_pword
declare -f _gids
declare -f _have
declare -f _included_ssh_config_files
declare -f _init_completion
declare -f _installed_modules
declare -f _ip_addresses
declare -f _kernel_versions
declare -f _known_hosts
declare -f _known_hosts_real
declare -f _longopt
declare -f _mac_addresses
declare -f _minimal
declare -f _modules
declare -f _ncpus
declare -f _parse_help
declare -f _parse_usage
declare -f _pci_ids
declare -f _pgids
declare -f _pids
declare -f _pnames
declare -f _quote_readline_by_ref
declare -f _realcommand
declare -f _rl_enabled
declare -f _root_command
declare -f _service
declare -f _services
declare -f _shells
declare -f _signals
declare -f _split_longopt
declare -f _sysvdirs
declare -f _terms
declare -f _tilde
declare -f _uids
declare -f _upvar
declare -f _upvars
declare -f _usb_ids
declare -f _user_at_host
declare -f _usergroup
declare -f _userland
declare -f _variables
declare -f _xfunc
declare -f _xinetd_services
declare -f add
declare -f command_not_found_handle
declare -f dequote
declare -f divide
declare -f gawklibpath_append
declare -f gawklibpath_default
declare -f gawklibpath_prepend
declare -f gawkpath_append
declare -f gawkpath_default
declare -f gawkpath_prepend
declare -f multiple
declare -f quote
declare -f quote_readline
declare -f reduce
|
-a 数组的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
lyr@DESKTOP-FSVN6C0:~$ arr=("a","b","c","d")
lyr@DESKTOP-FSVN6C0:~$ echo ${#arr[@]}
1
lyr@DESKTOP-FSVN6C0:~$ echo ${arr[2]}
lyr@DESKTOP-FSVN6C0:~$ echo ${#arr[2]}
0
lyr@DESKTOP-FSVN6C0:~$ echo ${#arr[1]}
0
lyr@DESKTOP-FSVN6C0:~$ echo ${#arr[@]}
1
lyr@DESKTOP-FSVN6C0:~$ echo ${arr[@]}
a,b,c,d
lyr@DESKTOP-FSVN6C0:~$ arr=("a" "b" "c" "d")
lyr@DESKTOP-FSVN6C0:~$ echo ${#arr[@] } && echo ${#arr[1]} && echo ${arr[0]}
-bash: ${#arr[@] }:错误的替换
lyr@DESKTOP-FSVN6C0:~$ echo ${#arr[@]} && echo ${#arr[1]} && echo ${arr[0]}
4
1
a
# 注意了, 数组要用 空格分开元素,大坑
|
expr 的两种方法
expr $num1 operator $num2
$(($num operator $num2))
read 读入用户输入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
lyr@DESKTOP-FSVN6C0:~$ read -p "input your num " w && echo $w
input your num 666666
666666
lyr@DESKTOP-FSVN6C0:~$ expr $w \> 0
1
lyr@DESKTOP-FSVN6C0:~$ expr $w \< 0
0
lyr@DESKTOP-FSVN6C0:~$ expr $w >= 0
expr: 语法错误:未预期的参数 “0”
lyr@DESKTOP-FSVN6C0:~$ expr $w \>= 0
1
lyr@DESKTOP-FSVN6C0:~$ expr $w \<= 0 &> /dev/null
lyr@DESKTOP-FSVN6C0:~$ echo $?
1
lyr@DESKTOP-FSVN6C0:~$ expr $w \>= 0 &> /dev/null
lyr@DESKTOP-FSVN6C0:~$ echo $?
0
# 如果用 $? 的方式 ,就是反过来了
|
求和脚本
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
|
#!/bin/bash
#Author:LYR
#Time:2021-10-03 17:35:05
#Name:app.sh
read -p "input your n: " n
# 判断是不是整数, n 和 任意一个数加法运算, 如果成功 $? 返回 0 ,如果失败异常,返回 1
expr $n + 1 &> /dev/null
if [ $? -eq 0 ] ;then
# 这个 expr 和 上面那个是反过来的
if [ `expr $n \> 0 ` -eq 1 ] ; then
for ((i=1;i<=$n;i++ ))
do
sum=`expr $sum + $i`
done
fi
else
echo "非法输入"
fi
echo $sum
|
1
2
3
4
5
6
7
8
|
lyr@DESKTOP-FSVN6C0:~$ ./app.sh
input your n: fuck
非法输入
lyr@DESKTOP-FSVN6C0:~$ ./app.sh
input your n: 100
5050
|
bc 命令运算
bc 是个交互型的内置的运算器,相当于 windows下的计算器,比较方便
1
2
3
4
5
6
7
8
9
10
11
12
13
|
lyr@DESKTOP-FSVN6C0:~$ bc
bc 1.07.1
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
1 + 1
2
+
(standard_in) 2: syntax error
4+5
9
26.00 + 44.1
70.10
|
shell脚本下使用 bc 命令
1
2
3
4
5
6
7
8
9
|
lyr@DESKTOP-FSVN6C0:~$ echo "44+44" | bc
88
lyr@DESKTOP-FSVN6C0:~$ a=`echo "44+44" | bc` && echo $a
88
lyr@DESKTOP-FSVN6C0:~$ a=`echo "$a+44" | bc` && echo $a
132
lyr@DESKTOP-FSVN6C0:~$ a=`echo "scale=6;$a*44.44444" | bc` && echo $a
5866.66608
# 这里 通过 scale 指定精确度
|