[华为云在线课程][Shell脚本编程基础][第二章Shell脚本语言的基本用法][2变量][学习笔记]

举报
John2021 发表于 2022/04/15 10:08:26 2022/04/15
【摘要】 变量 变量变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据 变量类型变量类型:内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE用户自定义变量不同的变量存放的数据不同,决定了以下数据存储方式参与的运算表示的数据范围变量数据类型:字符数值:整型、浮点型,bash不支持浮点数 编程语言分类静态和动态语言静态编译...

变量

变量

变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据

变量类型

变量类型:

  • 内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE
  • 用户自定义变量

不同的变量存放的数据不同,决定了以下

  • 数据存储方式
  • 参与的运算
  • 表示的数据范围

变量数据类型:

  • 字符
  • 数值:整型、浮点型,bash不支持浮点数

编程语言分类

静态和动态语言

  • 静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:Java,C
  • 动态编译语言:不用事先声明,可随时改变类型,如:bash,Python

强类型和弱类型语言

  • 强类型语言:不同类型数据操作,必须经过强制转换为同一类型才能运算,如Java,C#,Python。
  • 弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用,如:bash,php,JavaScript。

shell中变量命名法则

1,不能使用程序中的保留字和内置变量,如:if,for
2,只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线"-",和主机名相反
3,见名知意,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
4,统一命名规则:驼峰命名法,studentname,大驼峰StudentName,小驼峰studentName
5,变量名大写:STUDENT_NAME
6,局部变量小写
7,函数名小写

变量定义和引用

变量的生效范围等标准划分变量类型

  • 普通变量:生效范围为当前shell进程;对当前shell之外的其他shell进程,包括当前shell的子shell进程均无效
  • 环境变量:生效范围为当前shell进程及其子进程
  • 本地变量:生效范围为当前shell进程中某代码片段,通常指函数

变量赋值:

name='value'

value可以是以下多种形式

直接字符串:name='root'
变量引用:name='$USER'
命令引用:name=`COMMAND` 或者 name=$(COMMAND)

注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束而删除。

变量引用:

$name
${name}

弱引用和强引用

  • “$name” 弱引用,其中的变量引用会被替换为变量值
  • ‘$name’ 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
    例子:变量的各种赋值方式和引用
[root@localhost Code]# echo $TITLE
cto
[root@localhost Code]# echo I am $TITLE
I am cto
[root@localhost Code]# echo "I am $TITLE"
I am cto
[root@localhost Code]# echo 'I am $TITLE'
I am $TITLE

[root@localhost Code]# echo $USER
root
[root@localhost Code]# NAME=$USER
[root@localhost Code]# echo $NAME
root

[root@localhost Code]# FILE=`ls /run`
[root@localhost Code]# echo $FILE
abrt auditd.pid console crond.pid cron.reboot cryptsetup dbus dhclient-ens33.pid dmeventd-client dmeventd-server faillock httpd initramfs lock log lvm lvmetad.pid mount netreport NetworkManager plymouth sepermit setrans sshd.pid sudo svnserve syslogd.pid systemd tmpfiles.d tuned udev user utmp vmware

[root@localhost Code]# FILE=/etc/*
[root@localhost Code]# echo $FILE
/etc/abrt /etc/adjtime /etc/aliases /etc/aliases.db /etc/alternatives /etc/anacrontab /etc/asound.conf /etc/audisp /etc/audit /etc/bash_completion.d /etc/bashrc /etc/binfmt.d /etc/centos-release

[root@localhost Code]# seq 5
1
2
3
4
5
[root@localhost Code]# NUM=`seq 5`
[root@localhost Code]# echo $NUM
1 2 3 4 5
[root@localhost Code]# echo "$NUM"
1
2
3
4
5

[root@localhost Code]# NAMES="zhao
> qian
> sun
> li"
[root@localhost Code]# echo $NAMES
zhao qian sun li
[root@localhost Code]# echo "$NAMES"
zhao
qian
sun
li

例子:变量引用

[root@localhost Code]# NAME=hello
[root@localhost Code]# AGE=20
[root@localhost Code]# echo $NAME
hello
[root@localhost Code]# echo $AGE
20
[root@localhost Code]# echo $NAME $AGE
hello 20
[root@localhost Code]# echo $NAME$AGE
hello20
[root@localhost Code]# echo $NAME_$AGE
20
[root@localhost Code]# echo {$NAME}_$AGE
{hello}_20

例子:变量的间接赋值和引用

[root@localhost Code]# TITLE=cto
[root@localhost Code]# NAME=hello
[root@localhost Code]# TITLE=$NAME
[root@localhost Code]# echo $NAME
hello
[root@localhost Code]# echo $TITLE
hello
[root@localhost Code]# NAME=nihao
[root@localhost Code]# echo $NAME
nihao
[root@localhost Code]# echo $TITLE
hello

例子:变量追加值

[root@localhost Code]# TITLE=cto
[root@localhost Code]# TITLE+=:hello
[root@localhost Code]# echo $TITLE
cto:hello

例子:利用变量实现动态命令

[root@localhost Code]# CMD=hostname
[root@localhost Code]# $CMD
localhost.localdomain

显示以定义的所有变量:

set

删除变量

unset <name>

例子:

[root@localhost Code]# unset AGE TITLE
[root@localhost Code]# unset NAME

例子:显示系统信息
注意:如果系统采用最下安装,那么需要先安装yum install net-tools才能使用ifconfig

[root@localhost Code]# cat systeminfo.sh
#!/bin/bash

RED="\E[1;31m"
GREEN="\E[1;32m"
END="\E[0m"
echo -e "$GREEN----------------Host systeminfo------------------$END"
echo -e "HOSTNAME:           $RED`hostname`$END"
echo -e "IPADDR:             $RED`ifconfig ens33|head -n2|tail -n1|tr -s ' '|cut -d " " -f3 `$END"
echo -e "OSVERSION:          $RED`cat /etc/redhat-release`$END"
echo -e "KERNEL:             $RED`uname -r`$END"
echo -e "CPU:               $RED`lscpu|grep 'Model name'|tr -s ' '|cut -d : -f2`$END"
echo -e "MEMORY:             $RED`free -h|grep Mem|tr -s ' ' :|cut -d : -f2`$END"
echo -e "DISK:               $RED`lsblk | grep '^sd' | tr -s ' '|cut -d ' ' -f4`$END"
echo -e "$GREEN-------------------------------------------------$END"

环境变量

1,可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
2,一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
3,一般只在系统配置文件中使用,在脚本中较少使用

变量声明和赋值:

# 声明并赋值
export name=VALUE
declare -x name=VALUE

# 或者分两步实现
name=VALUE
export name

变量引用:

$name
${name}

显示所有环境变量:

env
printenv
export
declare -x

删除变量:

unset name

bash内建的环境变量

PATH
SHELL
USER
UID
HOME
PWD
SHLVL #shell的嵌套层数,即深度
LANG
MAIL
HOSTNAME
HISTSIZE
_ #下划线,表示前一命令的最后一个参数

只读变量

只读变量:只能声明定义,但后续不能修改和删除,即常量
声明只读变量:

readonly name
declare -r name

查看只读变量:

readonly [-p]
declare -r

例子:

[root@localhost Code]# readonly PI=3.14159
[root@localhost Code]# echo $PI
3.14159
[root@localhost Code]# PI=3.14
-bash: PI: readonly variable
[root@localhost Code]# unset PI
-bash: unset: PI: cannot unset: readonly variable
[root@localhost Code]# echo $PI
3.14159

#退出PuTTY后重新登录
[root@localhost ~]# echo $PI

[root@localhost ~]#

位置变量

位置变量:在bash shell中内置的变量,在脚本代码中调用通过命令行传递给脚本的参数

$1,$2,...      对应第1个、第2个参数,shift [n]换位置
$0             命令本身,包括路径
$*             传递给脚本的所有参数,全部参数合为一个字符串
$@             传递给脚本的所有参数,每个参数为独立字符串
$#             传递给脚本的参数的个数

注意:$@ $*     只在被双引号包起来的时候才会有差异

清空所有位置变量

set --

例子:

[root@localhost Code]# cat arg.sh
#!/bin/bash
echo 1st arg is $1
echo 2st arg is $2
echo 3st arg is $3
echo 10st arg is $10 #输出结果和下一条指令有什么区别
echo 10st arg is ${10}
echo All args are $*
echo All args are $@
echo the arg number is $#
echo the scriptname is $(basename $0)

[root@localhost Code]# ./arg.sh {a..z}
1st arg is a
2st arg is b
3st arg is c
10st arg is a0
10st arg is j
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
the arg number is 26
the scriptname is arg.sh

例子:删库跑路之指令rm的安全实现

[root@localhost hello]# cat Code/rm.sh
#!/bin/bash
WARNING_COLOR="echo -e \E[1;31m"
END="\E[0m"
DIR=/home/hello/Code/recycletmp/`date +%F_%H-%M-%S`
mkdir $DIR
mv $* $DIR
${WARNING_COLOR}Move $* to $DIR $END

[root@localhost Code]# ls
arg.sh  backup.sh  systeminfo.sh  vimrc-2022-04-14
[root@localhost Code]# mkdir recycletmp
[root@localhost Code]# ll
total 16
-rwxr--r-- 1 root root  222 Apr 15 07:10 arg.sh
-rwxr-xr-x 1 root root  161 Apr 14 16:54 backup.sh
drwxr-xr-x 2 root root    6 Apr 15 07:17 recycletmp
-rwxr-xr-x 1 root root  712 Apr 14 20:29 systeminfo.sh
-rw-r--r-- 1 root root 2062 Apr 14 16:54 vimrc-2022-04-14
[root@localhost Code]# vim rm.sh
[root@localhost Code]# ll
total 20
-rwxr--r-- 1 root root  222 Apr 15 07:10 arg.sh
-rwxr-xr-x 1 root root  161 Apr 14 16:54 backup.sh
drwxr-xr-x 2 root root    6 Apr 15 07:17 recycletmp
-rw-r--r-- 1 root root  152 Apr 15 07:19 rm.sh
-rwxr-xr-x 1 root root  712 Apr 14 20:29 systeminfo.sh
-rw-r--r-- 1 root root 2062 Apr 14 16:54 vimrc-2022-04-14
[root@localhost Code]# chmod a+x rm.sh
[root@localhost Code]# ll
total 20
-rwxr--r-- 1 root root  222 Apr 15 07:10 arg.sh
-rwxr-xr-x 1 root root  161 Apr 14 16:54 backup.sh
drwxr-xr-x 2 root root    6 Apr 15 07:17 recycletmp
-rwxr-xr-x 1 root root  152 Apr 15 07:19 rm.sh
-rwxr-xr-x 1 root root  712 Apr 14 20:29 systeminfo.sh
-rw-r--r-- 1 root root 2062 Apr 14 16:54 vimrc-2022-04-14
[root@localhost Code]# vim rm.sh
[root@localhost Code]# pwd recycletmp/
/home/hello/Code
[root@localhost Code]# vim rm.sh
[root@localhost Code]# alias rm='/home/hello/Code/rm.sh'
[root@localhost Code]# cd ..
[root@localhost hello]# ll
total 0
drwxr-xr-x. 3 root root 113 Apr 15 07:21 Code
[root@localhost hello]# touch {1..5}.txt
[root@localhost hello]# ls
1.txt  2.txt  3.txt  4.txt  5.txt  Code
[root@localhost hello]# rm *.txt
Move 1.txt 2.txt 3.txt 4.txt 5.txt to /home/hello/Code/recycletmp/2022-04-15_07-22-21

例子:$*$@的区别

[root@localhost Code]# cat f1.sh
#!/bin/bash
echo "f1.sh:all args are $@"
echo "f1.sh:all args are $*"

./file.sh "$*"
[root@localhost Code]# cat f2.sh
#!/bin/bash
echo "f2.sh:all args are $@"
echo "f2.sh:all args are $*"

./file.sh "$@"
[root@localhost Code]# cat file.sh
#!/bin/bash
echo "file.sh:1st arg is $1"

[root@localhost Code]# ./f1.sh a b c
f1.sh:all args are a b c
f1.sh:all args are a b c
file.sh:1st arg is a b c
[root@localhost Code]# ./f2.sh a b c
f2.sh:all args are a b c
f2.sh:all args are a b c
file.sh:1st arg is a

例子:利用软链接实现同一个脚本不同功能

[root@localhost Code]# cat test.sh
#!/bin/bash
#*********************************************
echo $0

[root@localhost Code]# ln --symbolic test.sh b.sh
[root@localhost Code]# ln --symbolic test.sh a.sh
[root@localhost Code]# ll
total 36
-rwxr--r-- 1 root root  222 Apr 15 07:10 arg.sh
lrwxrwxrwx 1 root root    7 Apr 15 07:33 a.sh -> test.sh
-rwxr-xr-x 1 root root  161 Apr 14 16:54 backup.sh
lrwxrwxrwx 1 root root    7 Apr 15 07:34 b.sh -> test.sh
[root@localhost Code]# ./a.sh
./a.sh
[root@localhost Code]# ./b.sh
./b.sh

退出状态码变量

当我们浏览网页时,有时会看到网页显示404,403之类的数字,表示网页的错误信息,我们称为状态码,在shell脚本中也有相似的技术表示程序执行的响应状态。
进程执行后,将使用变量$?保存状态码的相关数字,不同的值反应成功或失败,$?取值范围0-255

$?的值为0       #表示成功
$?的值是1-255   #表示失败

例子:

[root@localhost Code]# ping -c1 -W1 10.0.0.110 &> /dev/null
[root@localhost Code]# echo $?
0
[root@localhost Code]# ping -c1 -W1 10.0.0.111 &> /dev/null
[root@localhost Code]# echo $?
1

用户可以在脚本中使用以下命令自定义退出状态码

exit [n]

注意:

  • 脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
  • 如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果
  • 如果没有exit命令,即未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

展开命令行

展开命令执行顺序

把命令行分成单个命令词
展开别名
展开大括号的声明 {}
展开波浪符声明 ~
命令替换$()``
再次把命令行分成命令词
展开文件通配*?[abc]等
准备I/O重导向<>
运行命令

防止拓展

反斜线 \ 会使随后的字符按原意解释

例子:

[root@localhost Code]# echo Your cost: \$500
Your cost: $500

加引号来防止拓展

单引号 '' 防止所有拓展
双引号 "" 也可防止拓展,但是以下情况例外:$(美元符号)

变量拓展:

``      反引号,命令替换
\       反斜线,禁止单个字符拓展
!       叹号,历史命令替换

脚本安全和set

set命令:可以用来定制shell环境
$-变量
h:hashall,打开选项后,shell会将命令所在的路径hash下来,避免每次都要查询。通过set+h将h选项关闭
i:interactive-comments,包含这个选项说明当前的shell是一个交互式的shell。所谓的交互式shell,在脚本中,i选项是关闭的
m:monitor,打开监控模式,就可以通过job control来控制进程的停止,继续,后台或者前台执行等
B:braceexpand,大括号扩展
H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如"!!"返回
例子:

[root@localhost Code]# echo $-
himBH
[root@localhost Code]# set +h
[root@localhost Code]# echo $-
imBH
[root@localhost Code]# hash
-bash: hash: hashing disabled
[root@localhost Code]# set -h
[root@localhost Code]# echo $-
himBH
[root@localhost Code]# hash
hits    command
   4    /usr/bin/chmod
   7    /usr/bin/cat
   9    /usr/bin/vim
   1    /usr/bin/touch
   2    /usr/bin/ping
   1    /usr/bin/mkdir
   4    /usr/bin/ln
   1    /usr/bin/man
  15    /usr/bin/ls
   5    /usr/bin/clear

[root@localhost Code]# echo {1..5}
1 2 3 4 5
[root@localhost Code]# echo $-
himBH
[root@localhost Code]# set +B
[root@localhost Code]# echo $-
himH
[root@localhost Code]# echo {1..5}
{1..5}

set命令实现脚本安全

-u        在拓展一个没有设置的变量时,显示错误信息,等同set -o nounset
-e        如果一个命令返回一个非0退出状态值(失败)就退出,等同set -o errexit
-o        option 显示,打开或者关闭选项
          显示选项:set -o
          打开选项:set -o 选项
          关闭选项:set +o 选项
-x        当执行命令时,打印命令及其参数,类似bash -x

例子:

[root@localhost Code]# set -o
allexport       off
braceexpand     off
emacs           on
errexit         off
errtrace        off
functrace       off
hashall         on
histexpand      on
history         on
ignoreeof       off
interactive-comments    on
keyword         off
monitor         on
noclobber       off
noexec          off
noglob          off
nolog           off
notify          off
nounset         off
onecmd          off
physical        off
pipefail        off
posix           off
privileged      off
verbose         off
vi              off
xtrace          off
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。