shell编程_第二篇_变量

[TOC]

# 变量

## 一 变量介绍

### 1、什么是变量?

```bash
量指的是记录事物的状态

变指的是事物的状态是可以发生变化的

变量本质就是一种数据存取的机制,变量的数据都是存放于内存中的
```

### 2、变量的分类

```bash
1、变量可以分为两大类:环境变量(全局变量),普通变量(局部变量)

2、环境变量也叫作全局变量,可以再创建他们的shell及其衍生出来的任意子进程shell中使用,环境变量又可分为自定义环境变量和bash内置环境变量。
  
3、普通变量也叫作局部变量,只能在创建他们的shell函数或者脚本中使用。普通变量一般有开发者用户开发脚本时创建。

```

## 二 环境变量

### 1、环境变量

```bash
export -p #查看系统中的环境变量
export #定义全局变量
unset 变量名 #取消使用变量
```

### 2、环境变量与普通变量作用域不同

实验

```bash
[root@xiaowu ~]# a=1
[root@xiaowu ~]# echo $a
1
[root@xiaowu ~]# export aa=11
[root@xiaowu ~]# echo $aa
11

[root@xiaowu ~]# vim aa.sh
#!/bin/bash
echo $a
echo $aa
~
~
"aa.sh" [New] 11L, 303C written

[root@xiaowu ~]# sh -x aa.sh
+ echo

+ echo 11
11 

总结:
第一个echo为什么是空?因为a是父shell中定义的普通变量,无法在子shell中生效,所以echo $a 结果为空。

   第二个echo 11是怎么得来的?因为在父shell中使用export定义了aa全局变量=11,所以在使用sh执行脚本的时候,全局变量生效aa=11。
```

### 3、环境变量相关的配置文件

```bash
cat /etc/profile
cat /etc/bashrc
cat ~/.bashrc
cat ~/.bash_profile
cd /etc/profile.d/
```

### 4、环境变量配置的优先级

```bash
/etc/profile
~/.bash_profile
~/.bashrc
/etc/bashrc

ps:当你在4个文件中写入一个相同的变量时,读取优先级高的会覆盖低的
```

### 5、环境变量总结

```bash
变量名通常大写

可以在自身以及下属子shell中生效

常用export定义环境变量

出时echo $name 取消时unset name

如果希望定义环境变量永久生效,可以将它写入到环境变量配置文件中
```

### 6、为何要有变量?

​ 程序运行的本质就是一系列状态的变化,

```python
程序=数据+功能,
程序执行的本质就是一系列状态的变化,变是程序执行的直接体现,所以我们需要有一种机制能够反映或者说是保存下来程序执行时状态以及状态的变化。
# 比如:
英雄的等级为1,打怪升级(变)为10
僵尸的存活状态True,被植物打死了,于是变为False
人的名字为egon,也可以修改为Egon
```

## 三 普通变量

### 1、 先定义、后引用

先定义

```python
# 1、语法:变量名=值
# 2、注意:等号左右两边不能有空格!!!
# 3、例如:
[root@xiaowu ~]# name="xiaowu"
```

后引用

```python
[root@xiaowu ~]# name="xiaowu"
[root@xiaowu ~]# echo $name
xiaowu

注意:如果是打印百分比,建议使用${变量名}%
[root@xiaowu ~]# percent=33
[root@xiaowu ~]# echo ${percent}%
33%
```

### 2、删除变量

```python
[root@xiaowu ~]# a=111
[root@xiaowu ~]# echo $a
111
[root@xiaowu ~]# unset a
[root@xiaowu ~]# echo $a

[root@xiaowu ~]#
```

## 四 变量的三大组成部分

### 1、变量的组成

- 1、变量名:用来访问到变量值的

- 2、赋值符号:将变量值的内存地址绑定给变量名

- 3、变量值:即我们存的数据

### 2、变量中引号的使用

```bash
1、一般只有在变量的值包含空格的时候使用引号,单双引号的区别就在于是否可以解析特殊符号。

2、内容是纯数字、连续字符串时,定义的时候可以不加任何引号。

3、没有特殊情况的时候,用字符串对变量进行赋值时,一律使用双引号,特别是多个字符串中包含有空格时。

[root@xiaowu ~]# echo $USER
root
[root@xiaowu ~]# name="user = $USER"
[root@xiaowu ~]# echo $name
user = root

4、当处于特殊情况下时,需要将变量的值原样调用的时候,应使用单引号。

[root@xiaowu ~]# echo $USER
root
[root@xiaowu ~]# name='user = $USER'
[root@xiaowu ~]# echo $name
user = $USER


5、变量在赋值时可以使用反引号的方式,利用命令的处理结果对变量进行赋值,反引号可以提升处理的优先级,改变原有处理顺序。

```

### 3、变量名的命名规范

定义变量把数据存到内存中不是目的,目的是以后要取出来用,而变量名就是用来取变量值的,而变量的名字直接表明了所存值的意义,可见变量名的命名非常重要

```python
# 变量名的命令应该见名知意,同时遵循如下规则
以字母或下划线开头,剩下的部分可以是:字母、数字、下划线,最好遵循下述规范:
1.以字母开头
2.使用中划线或者下划线做单词的连接
3.同类型的用数字区分
4.对于文件名的命名最好在末尾加上拓展名

例如: sql_bak.tar.gz,log_bak.tar.bz2
5、不要带有空格、?、*等特殊字符
6、不能使用bash中的关键字,例如if,for,while,do等
7、不要和系统环境变量冲突
```

### 3.2 变量值的三种来源

**(1)直接赋值**

```python
# 1. 显式赋值:变量名=变量值
示例:
ip=10.0.0.200
where="Shanghai"
time1=`date +%F`
time2=$(date +%F)

# 2、应用示例
[root@xiaowu ~]# ip=10.0.0.200
[root@xiaowu ~]# echo $ip
10.0.0.200

[root@xiaowu ~]# where="shanghai"
[root@xiaowu ~]# echo $where
shanghai

[root@xiaowu ~]# time1=`date +%F`
[root@xiaowu ~]# echo $time1
2021-01-11

[root@xiaowu ~]# time2=$(date +%F)
[root@xiaowu ~]# echo $time2
2021-01-11

```

**(2)从位置参数获取变量值**

```python
从调用脚本时传入的位置参数获取变量值:./b.sh a1 a2 a3

$0 获取当前执行脚本的文件名,如执行时包含脚本路径信息,那么调用时也包含。( /server/xxx.sh )

$n 获取当前执行脚本的第N个参数,n=1-9,当n为0的时候表示脚本文件名,如果n大于9用大括号括起来{10},传参 参数以空格分隔。


# 示例
[root@xiaowu ~]# vim a.sh
#!/bin/bash
##############################################################
# File Name: a.sh
# Version: V1.0
# Author: xiaowu
# Create time: 2021-01-11 20:53
# Organization: https://www.cnblogs.com/pmstaw/
##############################################################

echo ${0}
echo $1
echo $2
echo $3
echo $4
echo $5
echo $6
echo $7
echo $8
echo $9
echo ${10}
echo ${11}
echo ${12}
~
"a.sh" [New] 22L, 385C written
[root@xiaowu ~]# ll
total 12
-rw-r--r-- 1 root root 303 Jan 11 12:00 aa.sh
-rw-r--r-- 1 root root 385 Jan 11 20:53 a.sh
-rw-r--r-- 1 root root 57 Jan 11 11:11 hello.sh
[root@xiaowu ~]# cat aa.sh
#!/bin/bash
##############################################################
# File Name: aa.sh
# Version: V1.0
# Author: xiaowu
# Create time: Mon 11 Jan 2021 11:59:56 AM CST
# Organization: https://www.cnblogs.com/pmstaw/
##############################################################

echo $a
echo $aa
[root@xiaowu ~]# sh ./a.sh a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15
./a.sh
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10
a11
a12
[root@xiaowu ~]#

# 企业使用:可以实现脚本的不同功能(服务程序管理脚本-启动功能 关闭功能 重启功能)
server.sh start|stop|restart
```

**(3)与用户交互获取值**

```python
何为交互,即输入、输出

# 一:read接收用户的输入,即从键盘读入变量值
read 变量名
read -p "提示信息: " 变量名
read -t 5 -p "提示信息: " 变量名 # -t指定秒数
read -n 2 变量名 # -n读取的字符个数

=======》应用示例:vim first.sh
[root@xiaowu ~]# vim firsh.sh
#!/bin/bash
##############################################################
# File Name: firsh.sh
# Version: V1.0
# Author: xiaowu
# Create time: 2021-01-11 20:56
# Organization: https://www.cnblogs.com/pmstaw/
##############################################################

read -p "请为输入一个名称:" name echo "你输入的名称是---》$name"
"firsh.sh" 11L, 357C written
[root@xiaowu ~]# sh firsh.sh
请为输入一个名称:111
你输入的名称是---》111

使用实践:
请写一个交互式的脚本,用户通过使用这个脚本可以实现更改主机名和网卡IP主机号。

网卡地址:
/etc/sysconfig/network-scripts/ifcfg-eth0
/etc/sysconfig/network-scripts/ifcfg-eth1

[root@xiaowu ~]# vim ip_hostname.sh
# Author: xiaowu
# Create time: 2021-01-11 21:06
# Organization: https://www.cnblogs.com/pmstaw/
##############################################################
ipaddr0=`ip a s eth0|awk -F"[ /.]+" 'NR==3{print $6}'`
ipaddr1=`ip a s eth1|awk -F"[ /.]+" 'NR==3{print $6}'`
file0=/etc/sysconfig/network-scripts/ifcfg-eth[0]
file1=/etc/sysconfig/network-scripts/ifcfg-eth[1]

echo "欢迎使用本脚本,此脚本为V1.0版本,如有不足,自行改进"
echo "===================================================="
read -p "请输入你要变更的主机名:" hostname
hostnamectl set-hostname $hostname
echo "当前主机名已变更为:" $hostname
echo "===================================================="
read -p "请输入你要将eth0 ip主机号修改为:" ip0
sed -i "s#$ipaddr0#$ip0#g" $file0

read -p "请输入你要将eth1 ip主机号修改为:" ip1
sed -i "s#$ipaddr1#$ip1#g" $file1
echo "===================================================="

systemctl restart network

```

```bash
# 二:输出
# 2.1 echo命令,详解情况:
[root@xiaowu ~]# name="xiaowu"
[root@xiaowu ~]# age=18
[root@xiaowu ~]# echo -e "my name is $name my age is $age"
my name is xiaowu my age is 18
[root@xiaowu ~]# echo "my name is $name my age is $age"
my name is xiaowu my age is 18


还可以输出带颜色(了解即可)
echo -e "33[31m 红色字 33[0m"
echo -e "33[33m 黄色字 33[0m"
echo -e "33[41;33m 红底黄字 33[0m"
echo -e "33[41;37m 红底白字 33[0m"

```

## 三 预定变量

### 1、位置变量

```bash

示例:

[root@xiaowu ~]# vim b.sh
echo "===$ #==="
echo $#
echo ""

echo "===$ @==="
echo $@
echo ""

echo "===$ *==="
echo $*
echo ""

echo "=====“$ *”和“$ @“====="
for i in "$*"
do
echo $i
done

echo "=============="

for i in "$@"
do
echo $i
done


[root@xiaowu ~]# sh b.sh a1 a2 a3 a4
===$ #===
4

===$ @===
a1 a2 a3 a4

===$ *===
a1 a2 a3 a4

=====“$ *”和“$ @“=====
a1 a2 a3 a4
==============
a1
a2
a3
a4

```

### 2、进程状态变量

```bash
$? 获取执行上一个指令的执行状态返回值(0表示成功,非零表示失败) *****
$$ 获取当前执行脚本的进程号(PID) # 此外,可以使用只读变量来获取父进程的PID:$PPID、获取执行脚本的用户ID:$UID
$_ 获取之前执行的命令或者脚本的最后一个参数
$! 获取上一个后台工作进程的进程号(PID)


示例:
[root@xiaowu ~]# vim ping.sh
#!/bin/bash
##############################################################
# File Name: ping.sh
# Version: V1.0
# Author: xiaowu
# Create time: 2021-01-12 11:30
# Organization: https://www.cnblogs.com/pmstaw/
##############################################################
ping -c1 baidu.com &>/dev/null
echo $?
echo $$
echo $!
echo $_


[root@xiaowu ~]# sh ping.sh
0
4208

echo

示例2:写一个脚本用来测试一个域名或地址可以ping通
[root@xiaowu ~]# vim ping_host.sh
#!/bin/bash
##############################################################
# File Name: ping_host.sh
# Version: V1.0
# Author: xiaowu
# Create time: 2021-01-12 11:40
# Organization: https://www.cnblogs.com/pmstaw/
##############################################################
read -p "你要ping的ip或域名" ip
ping -c2 $ip &>/dev/null
if [ $? = 0 ];then
echo "host $ip is ok"
else
echo "host $ip is fail"
fi
[root@xiaowu ~]# sh ping_host.sh
你要ping的ip或域名baidu.com
host baidu.com is ok
[root@xiaowu ~]# sh ping_host.sh
你要ping的ip或域名10.0.0.100
host 10.0.0.100 is fail


```

了解:

```python
如果我们想从命令行中获取脚本调用者传入的参数值,用$n可以取到,但如果脚本调用者在命令行传入的参数个数不固定,那么此时就需要用$*或$@来获取了

$*与$@获取的是所有位置参数,$0除外
```

当脚本调用者的传参形式如下是

```python
[root@localhost ~]# ./script.sh 命令1 命令2 命令3
```

针对for循环语句:for i in 元素,for循环会按照空格作为分隔符来一个个取元素,所以此时`$*`与`$@`并无区别

```python
[root@xiaowu ~]# vim b.sh
#!/bin/bash
##############################################################
# File Name: b.sh
# Version: V1.0
# Author: xiaowu
# Create time: 2021-01-12 11:08
# Organization: https://www.cnblogs.com/pmstaw/
##############################################################
echo "===$ @==="
for i in $@
do
echo $i
done

echo "========="


echo "===$ *==="
for i in $*
do
echo $i
done

echo "=========="

echo "=====“$ *”====="
for i in "$*"
do
echo $i
done

echo "=======“$ @”======="

for i in "$@"
do
echo $i
done


[root@xiaowu ~]# sh b.sh a1 a2 a3 a4 a5
===$ @===
a1
a2
a3
a4
a5
=========
===$ *===
a1
a2
a3
a4
a5
==========
=====“$ *”=====
a1 a2 a3 a4 a5
=======“$ @”=======
a1
a2
a3
a4
a5

```

当脚本调用者的传参形式如下时

```python
[root@localhost ~]# ./script.sh 命令1 命令2 "命令3 参数"
```

针对for循环语句:for i in 元素,for循环会按照空格作为分隔符来一个个取元素,所以此时`$*`与`$@`如果不加引号,第三个命令:"命令3 参数",为被以空格为分隔符识别成两部分

```python
[root@localhost ~]# cat script.sh
#!/bin/bash

for i in $*
do
echo $i
done

echo "=================="

for i in $@
do
echo $i
done
[root@localhost ~]#
[root@localhost ~]# ./script.sh 命令1 命令2 "命令3 参数"
命令1
命令2
命令3
参数
==================
命令1
命令2
命令3
参数
```

所以需要为`$*`与`$@`加上引号

```python
[root@localhost ~]# cat script.sh
#!/bin/bash

for i in "$*"
do
echo $i
done

echo "=================="

for i in "$@"
do
echo $i
done
[root@localhost ~]# ./script.sh 命令1 命令2 "命令3 参数"
命令1 命令2 命令3 参数
==================
命令1
命令2
命令3 参数
[root@localhost ~]#
```

但此时为`$*`就会把所有位置参数识别成一个整体,所以总结如下:

```python
当脚本调用者的传参形式如下时
[root@localhost ~]# ./script.sh 命令1 命令2 "命令3 参数"

需要使用"$@"来分别获取一个个完整的命令
for i in "$@"
do
echo $i
done

其余情况$*与$@完全一致
```

## 四 常量

相对于变量,常量就是不可以被改变的量,即只能读不能改,所以又称之为只读变量

```python
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
[root@xiaowu ~]# x=111
[root@xiaowu ~]# readonly x
[root@xiaowu ~]# x=66
-bash: x: readonly variable


```

原文地址:https://www.cnblogs.com/pmstaw/p/14261558.html