SHELL脚本中的变量与运算
SHELL脚本中的变量
什么是变量
在编写程序时,通常会遇到被操作对象不固定的情况
我们需要用一串固定的字符来表示不固定的值这就是变量存在的根本意义
变量的实现原理就是内存存储单元的一个符号名称
变量的命名规则
变量的名称中只能包含数字、大小写字母以及下划线
变量的名称只能用大小写字母及下划线开头
同一名称变量在多次被赋值时为覆盖动作
在企业代码规范化中变量的命名规则如下
简短全大写变量名、首字母大写子类变量名、驼峰类型变量名
变量的调用方法
$HEA #表示取$HEA这个变量的值
[root@localhost ~]# HEA=1
[root@localhost ~]# echo $HEA
1
如果我们想表示1b
$HEAb 这个变量调用方式是使用HEAb这串字符变量的值
${HEA}b 如果需要在一串字符中特别说明那些字符表示变量那些字符不是,那么需
要用变量声明${}
查看系统中的所有变量可以使用 env
查看系统中所有变量或函数可以使用set命令或declare
字符的转义及引用
在shell中有很多本身有特殊功能的字符,比如空格井号等等
如果在给变量赋值或执行命令使用时我们只想使用这些符号本身那么就需要用到转义或引用
在shell中反斜杠表示转义,每个反斜杠只能转义一个字符
在shell中单引号表示强引用,我们可以把它看作批量转义,在单引号内的所有字符被视为字符本身
在shell中双引号表示弱引用,其和单引号的区别在于不能引用(` \ ! $)
[root@localhost ~]# echo hello
hello
[root@localhost ~]# echo #hello
[root@localhost ~]# echo \#hello
#hello
[root@localhost ~]# echo \# #hello
#
[root@localhost ~]# echo \# \#hello
# #hello
[root@localhost ~]# echo "# #hello"
# #hello
[root@localhost ~]# echo '\ \$a'
\ \$a
[root@localhost ~]# echo "\ \$a"
\ $a
[root@localhost ~]# echo "\\$a"
\
变量的类型
从变量的作用范围来划分,变量分为函数级变量,环境级变量,用户级变量和系统级变量
函数级变量只在函数内生效通常用local来定义
[root@localhost Desktop]# vim test.sh
[root@localhost Desktop]# chmod +x test.sh
[root@localhost Desktop]# ./test.sh
1
#显示为空
[root@localhost Desktop]# ./test.sh
1
[root@localhost Desktop]# cat test.sh
#!/bin/bash
ACTION(){
local a=1
echo $a
}
ACTION
echo $a
环境级别变量只在当前运行的shell中生效,shell关闭变量被释放
[root@localhost Desktop]# export a=1
[root@localhost Desktop]# vim test.sh
[root@localhost Desktop]# sh test.sh
1
[root@localhost Desktop]# exit
[root@localhost Desktop]# sh test.sh
#显示为空
[root@localhost Desktop]# cat test.sh
#!/bin/bash
echo $a
用户级变量只有登录系统的指定用户,此变量才生效
[root@localhost Desktop]# useradd lee
[root@localhost Desktop]# vim ~lee/.bash_profile
export a=1
[root@localhost Desktop]# sh test.sh
#显示为空
[root@localhost Desktop]# su - lee
[root@localhost Desktop]# sh /root/Desktop/test.sh
1
系统级变量是系统中的永久设定,所有用户都可以使用,系统变量通常被保存到/etc/profile中
[root@localhost Desktop]# vim /etc/profile.d/a.sh
[root@localhost Desktop]# cat /etc/profile.d/a.sh
#!/bin/bash
export b=1
[root@localhost Desktop]# source /etc/profile.d/a.sh
[root@localhost Desktop]# vim test.sh
[root@localhost Desktop]# cat test.sh
#!/bin/bash
echo $b
[root@localhost Desktop]# sh test.sh
1
在系统中通常设置系统变量是编辑文件更加安全
文件修改完毕后需要用source命令使其生效
常见的系统及变量
在系统中被预设的变量如下
变量 | 说明 |
PATH | 命令的搜索路径,以冒号作为分隔符 |
HOME | 用户的家目录路径,是cd命令的默认参数 |
COLUMNS | 命令行编辑模式下可使用命令的长度 |
HISTFILE | 命令历史的文件路径 |
HISTFILESIZE | 命令历史中包含的最大行数 |
HISTSIZE | history命令输出的记录数 |
LOGNAME | USER | 当前用户的名字 |
SHELL |
当前使用的shell |
PWD | 当前的工作目录 |
PS1 | 命令行提示符变量 |
PATH指定命令执行路径是非常有用
如果我想在当前用户中可以用相对路径方式调用/mnt下的所有可执行文件[root@localhost Desktop]# vim ~/.bash_profile PATH=$PATH:/mnt [root@localhost Desktop]# source ~/.bash_profile [root@localhost Desktop]# echo $PATH /root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin: /mnt
特殊变量定义方式
用命令的执行结果定义变量
在执行命令时如果想让指定命令优先执行可以使用 $(cmd) 或 ``
[root@localhost Desktop]# echo your hostname is hostname
your hostname is hostname
[root@localhost Desktop]# echo your hostname is $(hostname)
your hostname is localhost.localdomain
[root@localhost Desktop]# echo your hostname is `hostname`
your hostname is localhost.localdomain
[root@localhost Desktop]# My_Hostname=`hostname`
[root@localhost Desktop]# mY_hOstname=$(hostname)
[root@localhost Desktop]# echo $My_Hostname $mY_hOstname
localhost.localdomain localhost.localdomain
传参变量
很多情况下,shell脚本需要接受用户的输入,根据用户的输入来执行不同的操作。
从命令行传递给shell脚本的参数又称为叫做位置参数,shell脚本会根据参数的位置使用不同的位置参数变量读取他们的值
变量 | 说明 |
$# | 命令行的参数个数 |
$0 | 当前脚本的名称 |
$n | 当前传递给脚本的第n个参数,比如$1表示脚本的第一个参数,$2表示脚本的第二个参数...... |
$* | 以“参数1 参数2 参数3”的形式返回所有参数的值 |
$@ | 以“参数1” “参数2” “参数3”的形式返回所有参数的值 |
[root@localhost Desktop]# ./test.sh hea Led linux
$0 is ./test.sh
$1 is hea
$2 is Led
$3 is linux
$# is 3
$* is hea Led linux
$@ is hea Led linux
[root@localhost Desktop]# cat test.sh
#!/bin/bash
echo '$0' is $0
echo '$1' is $1
echo '$2' is $2
echo '$3' is $3
echo '$#' is $#
echo '$*' is $*
echo '$@' is $@
[root@localhost Desktop]# vim touch.sh
[root@localhost Desktop]# chmod +x touch.sh
[root@localhost Desktop]# ls
test.sh touch.sh
[root@localhost Desktop]# ./touch.sh heath lerger
[root@localhost Desktop]# ls
'heath lerger' test.sh touch.sh
[root@localhost Desktop]# cat touch.sh
#!/bin/bash
touch "$*"
[root@localhost Desktop]# vim touch.sh
[root@localhost Desktop]# ./touch.sh heath lerger
[root@localhost Desktop]# ls
heath 'heath lerger' lerger test.sh touch.sh
[root@localhost Desktop]# cat touch.sh
#!/bin/bash
touch "$@"
[root@localhost Desktop]#
$? 表示上一条命令的退出值,0表示无任何问题,1-255 表示命令执行报错
$$ 表示当前进程的pid[root@localhost Desktop]# echo $$ 2295 [root@localhost Desktop]# echo $? 0 [root@localhost Desktop]# ps PID TTY TIME CMD 2295 pts/0 00:00:00 bash 2545 pts/0 00:00:00 ps [root@localhost Desktop]# ls haha ls: cannot access 'haha': No such file or directory [root@localhost Desktop]# echo $? 2
交互式传参
利用read命令可以和脚本执行者进行交互传参
示例:
交互赋值单个变量
[root@localhost Desktop]# read A
1
[root@localhost Desktop]# echo $A
1
交互赋值多个变量
[root@localhost Desktop]# read A B C
1 2 3
[root@localhost Desktop]# echo $A $B $C
1 2 3
交互赋值数组
[root@localhost Desktop]# read -a hea
hello heath linux
[root@localhost Desktop]# echo ${hea[0]}
hello
[root@localhost Desktop]# echo ${hea[1]}
heath
[root@localhost Desktop]# echo ${hea[2]}
linux
[root@localhost Desktop]# echo ${hea[*]}
hello heath linux
交互赋值并显示提示符
[root@localhost Desktop]# read -p "Please input word: " A
Please input word: hello
[root@localhost Desktop]# echo $A
hello
隐藏赋值内容
[root@localhost Desktop]# read -p "Please input word: " -s WORD
Please input word: [root@localhost Desktop]# echo $WORD
hello
设置超时时间
[root@localhost Desktop]# read -t 5 -p "Please input word: " WORD2
Please input word: [root@localhost Desktop]#
[root@localhost Desktop]# read -t 5 -p "Please input word: " WORD2
Please input word: hea
[root@localhost Desktop]# echo $WORD2
hea
设置赋值长度
Please input word: [root@lread -n 3 -p "Please input word: " WORD2
Please input word: hea[root@localhost Desktop]# echo $WORD2
hea
指定录入结束符
[root@localhost Desktop]# read -d "." a
123456.[root@localhost Desktop]# echo $a
123456
-a 读取的内容存入数组
-d 持续读取直到读入 DELIM 变量中的第一个字符,而不是换行符
-n/N 读取N个字符
-p 指定提示信息,用于等待输入
-r 不允许反斜杠转义任何字符
-s 从标准输入中读取密码而不在屏幕上显示输入的字符
-t 设置读取输入的超时时间,单位为秒
数组变量
我们可以定义变量为一组内容,中间的元素用空格隔开
[root@localhost Desktop]# A=(1 2 3 4 5)
[root@localhost Desktop]# echo ${A[0]}
1
[root@localhost Desktop]# echo ${A[1]}
2
[root@localhost Desktop]# echo ${A[*]}
1 2 3 4 5
[root@localhost Desktop]# echo ${A[@]}
1 2 3 4 5
取数组的最后一个元素
[root@localhost Desktop]# echo ${A[-1]}
5
取数组的第1-3个元素
[root@localhost Desktop]# echo ${A[*]:0:3}
1 2 3
查看数组的元素个数
[root@localhost Desktop]# echo ${#A[@]}
5
管理数组元素
[root@localhost Desktop]# A[0]=6
[root@localhost Desktop]# echo ${A[0]}
6
[root@localhost Desktop]# echo ${A[@]}
6 2 3 4 5
[root@localhost Desktop]# A[5]=6
[root@localhost Desktop]# echo ${A[@]}
6 2 3 4 5 6
[root@localhost Desktop]# unset A[0]
[root@localhost Desktop]# echo ${A[@]}
2 3 4 5 6
[root@localhost Desktop]# unset A
[root@localhost Desktop]# echo ${A[@]}
#显示为空
变量中字符串的取值管理
表达式 | 说明 |
${parameter} | 返回变量的内容 |
${#parameter} | 返回变量内容的长度(按字符) |
${paramater:offset} | 在变量${parameter}中,从位置offset之后开始提取子串到结尾 |
${paramater:offset:length} | 在变量${parameter}中,从位置offset之后开始提取长度为 length的子串 |
${parameter#word} | 从变量${parameter}开头开始删除最短匹配的word子串 |
${parameter##word} | 从变量${parameter}开头开始删除最长匹配的word子串 |
${parameter%word} | 从变量${parameter}结尾开始删除最短匹配的word子串 |
${parameter%%word} | 从变量${parameter}结尾开始删除最长匹配的word子串 |
${parameter/pattern/string} | 使用string代替第一个匹配的pattern |
${parameter//pattern/string} | 使用string代替所有匹配的pattern |
示例:
[root@localhost Desktop]# str="/easy/lee/test.tar.gz"
[root@localhost Desktop]# echo ${str}
/easy/lee/test.tar.gz
[root@localhost Desktop]# echo ${#str}
21
[root@localhost Desktop]# echo ${str:5}
/lee/test.tar.gz
[root@localhost Desktop]# echo ${str:1:3}
eas
[root@localhost Desktop]# echo ${str::3}
/ea
[root@localhost Desktop]# echo ${str:0-3:2}
.g
[root@localhost Desktop]# echo ${str:0-5}
ar.gz
[root@localhost Desktop]# echo ${str#*/}
easy/lee/test.tar.gz
[root@localhost Desktop]# echo ${str%%/*}
#输出为空
[root@localhost Desktop]# echo ${str##*/}
test.tar.gz
[root@localhost Desktop]# echo ${str%/*}
/easy/lee
[root@localhost Desktop]# echo ${str/./@}
/easy/lee/test@tar.gz
[root@localhost Desktop]# echo ${str//./@}
/easy/lee/test@tar@gz
脚本中的函数
变量是一个变化值的别名
函数就是一段程序的别名
代码无限循环
#!/bin/bash
ACTION(){
read -p "Please input word: " WORD
echo $WORD
ACTION
}
ACTION
解决代码重复
#!/bin/bash
echo -e "\033[31mred \033[0m"
echo -e "\033[32mgrean \033[0m"
echo -e "\033[33myello \033[0m"
echo "====== function ============="
ECHO ()
{
echo -e "\033[$1m$2\033[0m"
}
ECHO 31 red
ECHO 32 grean
ECHO 33 yello
取消变量
unset 变量 即可把变量取消
如果变量被记录到配置文件中需要在配置文件中删除记录
shell中的运算
shell中的运算命令
运算命令与符号 | 意义 | 说明 |
(()) | 用于整数运算的常用运算符 | 在(())中使用变量时可以去掉变量前的$符号 |
let | 用于整数运算 | 使用let命令可以执行一个或者多个算术表达式,其中的变量名毋需使用$符号 |
expr | 可用于整数运算,但还有很多其他的额外功能 | 使用expr时,运算符及用于计算的数字左右都至少有一个空格,否则会报错。 |
bc | linux下的一个计算器程序(适合整数及小数运算) | 系统中的计算器可以计算小数,二进制等 |
$[] | 用于整数运算 | |
awk | awk既可以用于整数运算,也可以用于小数运算 | |
declare | 定义变量值和属性,-i参数可以用于定义整形变量,做运算 |
[root@localhost Desktop]# let b=1+2
[root@localhost Desktop]# echo $b
3
[root@localhost Desktop]# ((a=1+1))
[root@localhost Desktop]# echo $a
2
[root@localhost Desktop]# echo $((a=1+1))
2
[root@localhost Desktop]# expr 1\*3
1*3
[root@localhost Desktop]# expr 1 \* 3
3
[root@localhost Desktop]# echo "scale=2;1/2" |bc
.50
[root@localhost Desktop]# echo "obase=2;ibase=10;2" |bc
10
[root@localhost Desktop]# echo "obase=2;ibase=10;3" |bc
11
[root@localhost Desktop]# echo $[1+1]
2
[root@localhost Desktop]# awk 'BEGIN{print 1.88/29}'
0.0648276
[root@localhost Desktop]# declare -i a=1+1
[root@localhost Desktop]# echo $a
2
shell中的数学运算符号
运算符 | 说明 |
+、- | 求和、求差 |
*、/、% | 求乘积,商,余数 |
** | 幂运算,例如3**3是求3的立方,即27 |
+=、-=、*=、/=、%= | 例a+=1相当于a=a+1 |
++variable、--variable | 先将变量variable的值加1,然后再赋给variable; 先将变量variable的值减1,然后再赋给variable |
variable++、variable-- |
先使用variable的值,然后再将该变量的值加1; 先使用variable的值,然后再将该变量的值减1 |
[root@localhost Desktop]# echo $((1+1))
2
[root@localhost Desktop]# echo $((2-1))
1
[root@localhost Desktop]# echo $((2 * 2))
4
[root@localhost Desktop]# echo $((2**3))
8
[root@localhost Desktop]# vim lee.sh
[root@localhost Desktop]# sh lee.sh
1
3
6
10
15
[root@localhost Desktop]# cat lee.sh
#!/bin/bash
for i in {1..5}
do
((n+=i))
echo $n
done
[root@localhost Desktop]# for ((n=1;n<=5;n++))
> do
> echo $n
> done
1
2
3
4
5
位运算
什么是位运算
程序中的所有数在计算机内存中都是以二进制的形式储存的
位运算就是直接对整数在内存中的二进制位进行操作
二进制的负数表示方法
2进制表示数字正负时最高位为0表示正数,最高位1表示负数
源码:负数的源码为负数绝对值的二进制数字,整数的源码为本身的二进制
反码:负数绝对值源码取反,但是表示正负的高位值不变
补码:反码+1为补码,补码即为负数二进制表示方式
计算结果超过8位舍弃超过的高位,特殊需要情况下使用扩展8位
1 的二进制源码 0000 0001
-1 的二进制原码 1000 0001
1 的反码 0000 0001
-1 的反码 1111 1110
1 的二进制码 0000 0001
-1 的二进制码 1111 1110+0000 0001 = 11111111
负数补码的原因是为了可以让加法器同时可以运算加法和减法
以时钟位例子
我想把8点调到10点: 顺时针8+2 逆时针8-10
最终时针的位置计算公式;
8+(顺时针调正的格数|神秘数字-逆时针调整的格子)=最终位置
神秘数字是时钟显示里最大数字+1
位逻辑运算
数A | <<1 | >>1 | a<<=1 | a>>=1 |
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 0 |
1 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 1 |
00001 1
00010 2
00100 4
01000 8
10000 16
位逻辑运算即将 1 左移或右移
<<=是复合左移运算符,a<<=1含义是a=a<<1
>>=是复合右移运算符,a<<=1含义是a=a>>1
root@heathle:~# echo $((2<<1))
4
root@heathle:~# echo $((2>>1))
1
root@heathle:~# a=2
root@heathle:~# echo $((a>>=1))
1
root@heathle:~# echo $a
1
root@heathle:~# a=2
root@heathle:~# echo $((a<<=1))
4
root@heathle:~# echo $a
4
数A | 数B | a&b | a | b | a^b | ~a |
0 | 0 | 0 | 0 | 0 | 1 |
0 | 0 | 0 | 0 | 0 | 1 |
0 | 1 | 0 | 1 | 1 | 1 |
1 | 0 | 0 | 1 | 1 | 0 |
& 与 只要一个数为 0 结果就为 0
| 或 只要一个数为 1 结果就为 1
^ 异或 相同取 0 ,相异取 1
~ 取反 按位取反
~ 运算符会对操作数的每一位进行取反操作,即
0
变为1
,1
变为0
。所以2
(00000010)按位取反后得到11111101,
在有符号整数的表示中,通常最高位为符号位,0
正,1
负。对于11111101
,最高位是1
,所以表示一个负数。在计算机中,负数是以补码的形式存储和运算的。要将补码转换为原码,需要先对补码进行减 1 操作,再对结果取反。
对于
11111101
,减 1 后得到11111100
,再取反得到00000011
,转换为十进制就是3
,所以11111101
表示的十进制数就是-3
[root@localhost ~]# echo $((1&2))
0
[root@localhost ~]# echo $((1|2))
3
[root@localhost ~]# echo $((1^2))
3
[root@localhost ~]# echo $((~1))
-2
[root@localhost ~]# echo $((~2))
-3
数A | A&=2 | A|=2 | A^=2 |
0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 |
1 | 0 | 1 | 1 |
&= 复合赋值运算 a&=2等价与a=a&2
[root@localhost ~]# a=1
[root@localhost ~]# ((a&=2))
[root@localhost ~]# echo $a
0
[root@localhost ~]# a=1
[root@localhost ~]# ((a|=2))
[root@localhost ~]# echo $a
3
[root@localhost ~]# a=1
[root@localhost ~]# ((a^=2))
[root@localhost ~]# echo $a
3