1. shell变量

Shell支持自定义变量。

1.1. 定义变量

定义变量时,变量名不加美元符号($),如:

1
variableName="value"

注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:

  • 首个字符必须为字母(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 命令可以删除变量。语法:

1
unset variable_name

变量被删除后不能再次使用;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” 的形式输出所有参数。 但是当它们被双引号(" “)包含时,

  • “$*” 会将所有的参数作为一个整体,以”$1 $2 … $n"的形式输出所有参数;

  • “$@” 会将各个参数分开,以"$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可以先执行命令,将输出结果暂时保存,在适当的地方输出。 命令替换的语法:

1
`command`

注意是反引号,不是单引号,这个键位于 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

变量测试

image-20211003185854884

参考:

变量的作用域

  • 不做特殊声明 ,shell中的变量都是全局变量
  • tips: 大型脚本程序中函数 中慎用全局变量
    • 局部变量的使用方法
      • local 关键字声明
1
2
3
4
5
6
function test
{
	local s=88
	echo $s

}

有类型变量

有类型变量声明

  1. declare -r # 声明为只读变量
  2. declare -i # 整形,int
  3. declare -f # 定义为函数和内容
  4. declare -F # 在脚本定义的函数
  5. 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 的两种方法

  1. expr $num1 operator $num2
  2. $(($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 指定精确度