Shell ❀ 基础变量类别与引用
Posted 无糖可乐没有灵魂
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell ❀ 基础变量类别与引用相关的知识,希望对你有一定的参考价值。
文章目录
二、变量与引用
变量是程序设计语言中的一个可以变化的量,变化的是变量的值。变量几乎所有的程序设计语言都有定义,并且其涵义也基本一致。在程序执行的过程中,保存数据的内存空间的内容可能会不断地发生变化,但是代表内存地址的变量名却保持不变。
1、变量命名
在shell中对于变量名称的规范如下:
- 变量名可以由字母、数字、下划线组成,只能以字母与下划线开头;
- 变量名的长度没有直接的规定,尽可能使用较短的字符串作为变量名。
2、变量类型
shell是一种动态类型语言和弱类型语言,在shell中,变量的数据类型不需要声明,变量的数据类型会根据不同的操作有所变化,shell中的变量是不分数据类型的,统一按照字符串存储。
弱类型语言与强类型语言(php
、C
、Python
都是强类型语言)
- 强类型和弱类型主要是站在变量类型处理的角度进行分类的;
- 强类型是指不允许隐式变量类型转换,弱类型则允许隐式类型转换;
3、变量定义
在shell中,当用户第一次使用某个变量名时,就同时定义了该变量名称,在变量的作用域内都可以使用此变量。
=
前后不能有空格
[root@localhost shell]# a= 3
bash: 3: command not found...
[root@localhost shell]# a =3
bash: a: command not found...
[root@localhost shell]# a=3
[root@localhost shell]# echo $?
0
[root@localhost shell]# echo $a
3
- 字符串类型建议用引号,尤其是特殊字符或有空格
# #号为注释符号,若不带引号则后面内容被注释,代码无效
[root@localhost ~]# echo #aaa
[root@localhost ~]# echo "#aaa"
#aaa
4、常用变量
主要有:通配符、内置变量、自定义变量、环境变量、全局变量、局部变量、位置变量、预定义变量。
4.1 内置通配符
在Linux系统中,通配符是一种特殊语句,主要有星号*
和问号?
,用来模糊搜索文件。当查找文件夹时,可以使用它来代替一个或多个真正字符;当不知道真正字符或者懒得输入完整名字时,常常使用通配符代替一个或多个真正的字符。
?
代表单个任意字符;*
代表多个任意字符。[]
匹配括号内任意一个字符;[-]
代表某个范围内的单个字符;[*]
匹配不是中括号的字符;
案例演示:
# 准备环境
[root@localhost shell]# touch a,b,c,tt.cc
[root@localhost shell]# ls
a b c tt.cc
# 匹配单个或多个字符
[root@localhost shell]# ls *.cc
tt.cc
[root@localhost shell]# ls ??.cc
tt.cc
# 匹配a或b单个字符
[root@localhost shell]# ls [ab]
a b
# 匹配范围a-b的单个字符
[root@localhost shell]# ls [a-b]*
a b
# 匹配非范围a-b的所有字符
[root@localhost shell]# ls [!a-b]*
c tt.cc
4.2 内置变量
内置变量:系统本来就存在的变量,可直接使用的。在执行脚本的时候,可通过带参数传入脚本内部。
常见内置变量有:
-
USER
:当前系统登录用户; -
UID
: 当前用户的UID; -
HOME
: 当前用户的家目录; -
SHELL
: 当前使用的shell类型 /bin/bash; -
BASHPID
: 当前bash的进程编号; -
HISTSIZE
: 缓冲区记录命令历史的数量; -
MAIL
: 当前用户的邮件信息储存目录/var/spool/mail/root
; -
PATH
: 当前系统环境变量; -
LANG
: 系统使用的语言和编码字符集en_US.UTF-8
; -
RANDOM
: 生成随机数,生成范围0~32767
; -
PS1
: 命令提示符; -
OSTYPE
: 操作系统类型 linux-gun; -
HOSTTYPE
: 主机类型 x86_64; -
MACHTYPE
: 机器类型 x86_64-redhat-linux-gnu;
[root@localhost ~]# echo $USER
root
[root@localhost shell]# echo $UID
0
[root@localhost shell]# echo $HOME
/root
[root@localhost shell]# echo $SHELL
/bin/bash
[root@localhost shell]# echo $BASHPID
2821
[root@localhost shell]# echo $HISTSIZE
1000
[root@localhost shell]# echo $MAIL
/var/spool/mail/root
[root@localhost shell]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost shell]# echo $RANDOM
3412
[root@localhost shell]# echo $PS1
[\\u@\\h \\W]\\$
[root@localhost shell]# echo $OSTYPE
linux-gnu
[root@localhost shell]# echo $HOSTTYPE
x86_64
[root@localhost shell]# echo $MACHTYPE
x86_64-redhat-linux-gnu
4.3 自定义变量
根据自己喜好所定义的变量。
-
定义变量:
变量名=变量值
-
引用变量:
$变量名
、$变量名
-
查看变量:
echo $变量名
、set(所有变量,包括自定义变量与环境变量)
-
取消变量:
unset 变量名
(注:取消变量时不需要带$引用变量名称) -
作用范围:仅在当前脚本文件中有效
4.4 环境变量
环境变量是程序(操作系统命令和应用程序)的执行都需要运行环境,分为临时变量和永久变量。
# 使用命令export直接加入临时变量(系统重启后失效)
[root@localhost shell]# export back_dir2=/home/backup
# 修改系统加载文件加入永久变量
[root@localhost shell]# vim /etc/profile
export TEST_PATH=/etc
export PATH=$PATH:$TEST_PATH
[root@localhost ~]# source /etc/profile
# 查看所有环境变量
[root@localhost shell]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
# 查看单个环境变量
[root@localhost shell]# back_dir1=/home/backup
[root@localhost shell]# echo $back_dir1
/home/backup
4.5 变量的作用域
4.5.1 全局变量
全局变量可以在脚本中定义,也可以在函数中定义,脚本中定义的变量都是全局变量,其作用域从被定义开始一直到shell脚本结束或者被显示删除。
4.5.2 局部变量
与全局变量相比,局部变量的使用范围较小,通常仅限于某个程序段访问,在shell语言中,可以在函数内部通过local
关键字定义局部变量,函数参数也是局部变量。
[root@localhost ~]# vim shell.sh
#!/bin/bash
function test()
local aaa=123
echo "本地变量:$aaa"
test
echo "---------------"
echo "全局变量:$aaa"
[root@localhost ~]# sh shell.sh
本地变量:123
---------------
全局变量:
4.6 位置变量
位置变量顾名思义就是脚本后面所附加的具体位置参数,如sh test.sh 1 2 3 ...
,其中1、2、3分别对应的就是位置1的变量,位置2的变量,位置3的变量,以此类推。
$1、$2、$3、$4、$5、$6、$7、$8、$9
4.5.1 位置变量的左移操作
在某些脚本文件中,若定义了某个位置参数后,则该参数后续不会被使用,因此可以使用shift
命令左移位置变量,默认移动距离为1,使得变量的数字不用人为记忆就可以常用,写代码较为方便。
[root@localhost ~]# vim shell.sh
#!/bin/bash
echo "位置1的变量是:$1"
echo "位置2的变量是:$2"
shift 1
echo "位置3的变量是:$3"
shift 3
echo "位置7的变量是:$7"
[root@localhost ~]# sh shell.sh a b c d e f g h i j k
位置1的变量是:a
位置2的变量是:b
位置3的变量是:d # 实际是位置4的变量d,并不是c
位置7的变量是:k # 实际是位置11的变量k,并不是g
4.5.2 执行脚本父目录绝对路径的获取方式
使用dirname
可以直接获取脚本所处父目录的绝对路径
[root@localhost ~]# dirname test.sh
. # 表示当前目录
[root@localhost ~]# dirname /usr/local/lib/
/usr/local # 父目录绝对路径
注:dirname
与pwd
的区别说明:
[root@localhost ~]# cd /usr/local/lib
[root@localhost lib]# cat /root/test.sh
#!/bin/bash
echo "dirname $0"
path=$(dirname $0)
echo "$path"
pwd
[root@localhost lib]# sh /root/test.sh
dirname /root/test.sh
/root # dirname返回运行脚本的父目录绝对路径
/usr/local/lib # pwd返回执行脚本的当前绝对路径
4.7 预定义变量
Linux系统默认预先定义的位置变量
$0 # 0位置参数,返回所执行脚本的名称
$* # 所有参数,返回值为一个整体值,以空格连接所有参数
$@ # 所有参数,返回值会将所有位置的参数当做一个单独的字段,以回车连接所有参数
$# # 参数个数
$$ # 当前进程PID
$! # 上一个后台进程的PID
$? # 上一个命令的返回值,0代表成功,非0代表失败
4.8 脚本变量案例
位置变量
[root@localhost ~]# vim test.sh
#!/bin/bash
echo "脚本名称是:$0"
echo "第2个参数是:$2"
echo "所有参数是:$*"
echo "所有参数是:$@"
echo "参数个数是:$#"
echo "当前进程PID是:$$"
[root@localhost ~]# sh test.sh a b c d e f g
脚本名称是:test.sh
第2个参数是:b
所有参数是:a b c d e f g
所有参数是:a b c d e f g
参数个数是:7
当前进程PID是:4607
[root@localhost ~]# echo $?
0
预定义变量
[root@localhost shell]# cat a4.sh
#!/bin/bash
ping -c2 $1 &> /dev/null
if [ $? = 0 ];then
echo "host $1 is ok!"
else
echo "host $1 is down!"
fi
[root@localhost shell]# sh a4.sh 10.81.10.55
host 10.81.10.55 is ok!
[root@localhost shell]# echo $?
0
4.9 $*与$@的区别
[root@localhost shell]# set -- "I am" test command
# 返回值为一个整体值,以空格连接所有参数
[root@localhost shell]# for i in "$*";do echo $i;done
I am test command
# 返回值会将所有位置的参数当做一个单独的字段,以回车符连接所有参数
[root@localhost shell]# for i in "$@";do echo $i;done
I am
test
command
5、变量赋值与替换
5.1 变量和引号
shell语言中一共有三种引号,分别是单引号、双引号、反引号。
- 单引号:字符作为普通字符出现,强转义;
- 双引号:除了
$
、\\
、'
、"
四个符号外,其余字符作为普通字符对待; - 反引号:引号内的内容被解释的shell命令;
[root@localhost shell]# echo "user is $USER"
user is root
[root@localhost shell]# echo 'user is $USER'
user is $USER
[root@localhost shell]# echo "user is `whoami`"
user is root
[root@localhost shell]# echo 'user is `whoami`'
user is `whoami`
# 正确使用转义符
[root@localhost ~]# echo "aaa\\"bbb"
aaa"bbb
5.2 只读变量
将变量配置成为readonly
类型,该变量不可被更改内容,也不能unset
(不建议使用此操作);
readonly [-fap] [变量定义]
# -f 定义只读函数
# -a 定义只读数组变量
# -p 显示系统中全部的变量列表
演示案例:
[root@localhost ~]# readonly aaa=123
[root@localhost ~]# readonly -p |grep aaa
declare -r aaa="123"
# 只读变量无法通过unset取消
[root@localhost ~]# unset aaa
-bash: unset: aaa: cannot unset: readonly variable
5.3 变量运算
5.3.1 常见运算符
+
-
:加 减*
/
%
:乘 除 取余**
:幂次方++
--
:增加 减少!
&&
||
:非 与 或<
<=
>
>=
:小于 小于等于 大于 大于等于==
!=
=
:相等 不等 相当于<<
>>
:左移 右移~
|
&
^
:取反 按位异或 按位与 按位或=
+=
-+
*=
/+
%=
:赋值运算符,a+=1
相当于a=a+1
[root@localhost ~]# echo $((1+1))
2
[root@localhost ~]# echo $((8**2))
64
[root@localhost ~]# echo $((1++2))
3
[root@localhost ~]# echo $((1==2)) # 不等为0
0
[root@localhost ~]# echo $((1==1)) # 相等为1
1
5.3.2 常见运算命令
(())
:用于整数运算的常用运算符;let
:用于整数运算,类似于(())
;expr
:可用于整数运算;bc
:Linux下的一个计算器程序,适用于整数与小数运算;$[]
:用于整数运算;awk
:用于整数与小数运算;declare
:定义变量值和属性,-i 参数定义整形变量,做运算;
[root@localhost ~]# echo $((1+1))
2
[root@localhost ~]# echo $[ 1+2 ]
3
# 使用计算机小程序
[root@localhost shell]# 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'.
2+2
4
1+1
2
^C
(interrupt) Exiting bc.
# let运算符
[root@localhost shell]# vim 1.sh
#!/bin/bash
i=1
while [ $i -le 3 ]
do
echo "$i"
let i++ # 变量i叠加1
done
[root@localhost shell]# sh 1.sh
1
2
3
5.3.3 变量子串说明
$parameter
:返回变量$parameter
的内容;$#parameter
:返回变量$parameter
内容的长度(按字符计算,索引从1开始),适用特殊变量;$parameter:offset
:在变量$parameter
中,从位置offset
之后开始提取子串到结尾;$parameter: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 shell]# filename=testfile.tar.gz
# 返回变量内容
[root@localhost shell]# echo $filename
testfile.tar.gz
# 返回变量长度
[root@localhost shell]# echo $#filename
15
# 从第7字节开始提取子串到结尾
[root@localhost shell]# echo $filename:6
le.tar.gz
# 从开头匹配删除最短的.子串,即从开头匹配到第一个.的字符串删除,注意通配符*的位置
[root@localhost shell]# echo $filename#*.
tar.gz
# 从开头匹配删除最长的.子串,即从开头匹配到最后一个.的字符串删除
[root@localhost shell]# echo $filename##*.
gz
# 从结尾匹配删除最短的.子串,即从结尾匹配到第一个.的字符串删除
[root@localhost shell]# echo $filename%.*
testfile.tar
# 从结尾匹配删除最短的.子串,即从结尾匹配到最后一个.的字符串删除
[root@localhost shell]# echo $filename%%.*
testfile
# 使用zip替换tar,只替换匹配的第一个tar字符串
[root@localhost shell]# echo $filename/tar/zip
testfile.zip.gz
$parameter:-word
: 如果parameter
的变量值为空或未赋值,则会返回word
字符串并替代变量的值用途:如果变量未定义,则返回备用的值,防止变量为空值或因未定义而导致异常。
[root@localhost ~]# echo $var1
[root@localhost ~]# var2=$var1:-hello # 变量1为空,返回hello
[root@localhost ~]# echo $var2
hello
[root@localhost ~]# echo $var1
[root@localhost ~]# var1="hello"
[root@localhost ~]# echo $var1
hello
[root@localhost ~]# var2=$var1:-world # 变量1不为空,返回变量原内容
[root@localhost ~]# echo $var2
hello
[root@localhost ~]# unset var1 var2 # 清理变量(选择性操作)
$parameter:=word
:如果parameter
的变量值为空或未赋值,则设置这个变量值为word
,并返回其值。位置变量和特殊变量不适用。
[root@localhost ~]# var2=$var1:=world # 变量1为空,将world赋值给变量1和变量2
[root@localhost ~]# echo $var2
world
[root@localhost ~]# echo $var1
world
[root@localhost ~]# unset var1 var2
[root@localhost ~]# var1="hello"
[root@localhost ~]# var2=$var1:=world # 变量1不为空,将变量1的值hello赋值给变量2
[root@localhost ~]# echo $var2
hello
[root@localhost ~]# echo $var1
hello
$parameter:?word
:如果parameter
变量值为空或未赋值,那么word
字符串将被作为标准错误输出,否则输出变量的值。
[root@localhost ~]# var2=$var1:?world # 变量1为空,将world作为错误输出
-bash: var1: world
[root@localhost ~]# unset var1 var2
[root@localhost ~]# var1="hello"
[root@localhost ~]# var2=$var1:?world # 变量1不为空,将变量1的值hello赋值给变量2
[root@localhost ~]# echo $var2
hello
[root@localhost ~]# echo $var1
hello
$parameter:+word
:如果parameter
变量值为空或未赋值,则什么都不做,否则word
字符串将替代变量的值。
[root@localhost ~]# var2=$var1:+world # 变量1为空,无返回
[root@localhost ~]# echo $var2
[root@localhost ~]# unset var1 var2
[root@localhost ~]# var1="hello"
[root@localhost ~]# var2=$var1:+world # 变量1不为空,将world赋值给变量2
[root@localhost ~]# echo $var2
world
[root@localhost ~]# echo $var1
hello
5.3.4 操作案例
基本要求:删除7天前的过期数据备份,规定path
则删除path
路径下的过期文件,若不规定path
,则删除/tmp
目录下过期文件
[root@localhost shell]# cat a1.sh
#!/bin/bash
find $path:-/tmp -name "*.tar.gz" -type f -mtime +7 | xargs rm -f
#指定path或tmp路径下,后缀为.tar.gz的任意文件,创建时间为7天之后
#xargs 参数传输命令
#将寻找到的文件,以参数传递给rm命令进行删除
[root@localhost shell]# sh a1.sh /
6、输入与输出
在Linux中输入与输出的方式种类较多,此处介绍两种最常用的输入与输出方法,read
输入与echo
输出;
6.1 read输入
在Linux系统中,read
命令用于从标准输入读取数值,这个命令可以用来读取键盘的输入值,因此常用于shell编程中的输入语法;
6.1.1 命令格式
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
-a
:后跟一个变量,该变量会被认为是个数组,然后给其赋值,默认是以空格为分割符;-d
:后面跟一个标志符,其实只有其后的第一个字符有用,作为结束的标志;-p
:后面跟提示信息,即在输入前打印提示信息;-e
:在输入的时候可以使用命令补全功能;-n
:后跟一个数字,定义输入文本的长度,如-n2
意味限制输入字符为2
个字符;-r
:屏蔽\\
,若没有该选项,\\
作为一个转义字符,否则\\
就是个正常的字符无需进行转义(\\
);-s
:安静模式,在输入字符时不再屏幕上显示,例如login时输入密码无回显,等同于使用stty ‐echo
关闭回显功能,使用stty echo
打开回显功能;-t
:后面跟秒数,定义输入字符的等待时间,如-t 3
意味3秒内输入,常用于条件判断语句中的定时输入;-u
:后面跟fd
,从文件描述符中读入,该文件描述符可以是exec新开启的;
6.1.2 操作案例
- 使用
read
命令输入一个信息;
#!/bin/bash
echo "输入一个信息:"
# 默认有一个换行符
read aaa
echo "你输入的信息是:$aaa"
输出结果:
[root@localhost ~]# sh 1.sh
输入一个信息:
aaa
你输入的信息是:aaa
- 使用
-p
参数提供一个提示信息;
#!/bin/bash
read -p "输入一个信息:" aaa
echo "你输入的信息是:$aaa"
输出结果:
[root@localhost ~]# sh 1.sh
输入一个信息:aaa
你输入的信息是:aaa
- 使用
-t
参数指定输入时间限制;
#!/bin/bash
if read -t 5 -p "输入一个信息:" aaa;then
echo "你输入的信息是 $aaa"
else
echo "输入超时!"
fi
输出结果:
[root@localhost ~]# sh 1.sh #不输入任何信息,等待5s
输入一个信息:输入超时!
- 使用
-n
参数指定输入字符长度;
#!/bin/bash
read -n1 -p "Do you want to continue [Y/N]?" answer
case $answer in
Y | y)
echo "fine ,continue";;
# 若是需要换行,则需要给echo添加参数-e,支持正则表达式
# echo -e "\\nfine ,continue";;
N | n)
echo "ok,good bye";;
*)
echo "error choice";;
esac
输出结果:
[root@localhost ~]# sh 1.sh
Do you want to continue [Y/N]?yfine ,continue
- 使用
-s
参数指定输入信息不得回显在终端上(数据是显示的,read
命令将文本颜色设置为背景颜色从而导致无法查看),常用于密码输入等位置;
#!/bin/bash
read -s -p "请输入密码:" pass
echo -e "\\n密码是 $pass"
输出结果:
[root@localhost ~]# sh 4.sh
请输入密码:
密码是 aaa
- 使用
read
命令读取文件中的每一行内容;
#!/bin/bash
# 从第一行开始
count=1
# 读取内容赋值给line变量
cat test.txt | while read line
do
# 显示行号:内容
echo "Line $count:$line"
# 行号自增加
count=$[ $count + 1 ]
done
echo "finish"
输出结果:
[root@localhost ~]# sh 1.sh
Line 1:this is test
Line 2:this is test
finish
- 使用
-e
参数,输入时可以使用tab
键补全内容;
[root@localhost ~]# read -e -p "输入文件名:"
输入文件名:1.
1.py 1.sh
输入文件名:1.py
6.2 echo输出
Linux的echo
命令在shell编程中十分常见,echo
命令的功能是在终端上打印出一段文字;
6.2.1 命令格式
echo [--help][--version] 或 echo [Options][字符串]
-
-n
:不要输出衍生的新行, 不加此参数时默认输出时换行; -
-e
:启用反斜线转义解释; -
-E
:禁用反斜线转义解释(默认参数);
使用-e
参数后,echo
可以支持如下转义序列:
\\a
:发出警告声;\\b
:删除前一个字符;\\c
:不产生进一步输出,只输出\\c
之前的内容;\\f
:换行,但下一行内容起始位置和上一行从\\f
处换行的位置对齐,效果等同于\\v
;\\n
:换行,下一行内容和上一行内容对齐;\\r
:换行,光标移至行首,输出\\r
后面的内容;\\v
:换行,但下一行内容起始位置和上一行从\\v
处换行的位置对齐,效果等同于\\f
;\\t
:插入tab
水平制表符;\\
:反斜线,插入\\
反斜线字符,若转义的内容如\\t
,系统会将转义后的反斜杠与t
进行结合,生成为\\t
(制表符),从而实现tab
水平制表功能,因此就需要将\\t
分别转义,即\\\\ + \\t
(第一个\\
均为转义符号);\\nnn
:插入nnn
(八进制)所代表的ASCII字符;\\0NNN
:八进制值表示的字节NNN
(1到3个数字);\\xHH
:十六进制值表示的字节NNN
(1到2个数字);
6.2.2 操作案例
- 使用
-n
参数
[root@localhost ~]# echo -n aaa ; echo bbb ; echo ccc
aaabbb
ccc
- 使用
-e
参数
# \\b删除前一个字符a
[root@localhost ~]# echo -e "this is a\\b test"
this is test
# \\c只输出前面内容(回车字符也被删除)
[root@localhost ~]# echo -e "aaa\\c bbb ccc"
aaa[root@localhost ~]#
# \\f换行输出,下一行起始位置等于换行位置(等同于\\v)
[root@localhost ~]# echo -e "this is \\f test"
this is
test
# \\n换行符
[root@localhost ~]# echo -e "this is \\n test"
this is
test
# \\r切换到行首换行,使用\\r后面的est替换开始的thi
[root@localhost ~]# echo -e "this is t\\rest"
ests is t
以上是关于Shell ❀ 基础变量类别与引用的主要内容,如果未能解决你的问题,请参考以下文章