深入浅出的学习变量(局部、全局、系统、位置、只读变量... set 命令、export 命令、以及如何设置环境变量!)

文章目录

      • 变量?
      • 变量的赋值:
        • ①、静态语言 或 强类型
        • ②、动态语言 或 弱类型
      • 变量名命名规则?
      •  
      • ==bash 中 变量的种类:==
        • ①、局部变量:
          • ★ 如何使用局部变量?
          • ★ 如何证明局部变量的生效范围?
            • ①、首先 使用 set 命令查看所有变量:
            • ②、接着 使用 bash 命令 进入当前shell 的子shell 进程:
            • ③、然后 使用 pstree -p 来查看进程之间的树状关系图:
            • ④、最后 使用 exit 命令退出当前 shell进程:
        • ②、全局变量(环境变量):
          • ★ 常用的全局变量列表:
          • ★ 使用关键字 export 来定义全局变量:
          • ★ 使用 “declare -x” 定义全局变量:
          • ★ 使用 export 来查看所有环境变量:
          • ★ 使用 evn 命令 查看所有环境变量
          • ★☆★_注意:局部和全局变量只能父传子,子不能传父!
        • ③、特殊变量(系统变量):
          • ★ 系统变量图表:
          • ★ $* 和 $@ 的区别是什么?
        • ④、只读变量:
          • ★ 如何声明只读变量:
          • ★ 如何查看只读变量:
        • ⑤、位置变量:
          • ★ 使用   \$1...$n 来表示位置变量
          • ★ 简单使用 位置变量 和 系统变量做一个例子:
          • ★ 用 $10 等十位数作为位置变量的时候,使用 { } !
          • ★ 使用 shift 往前移动位置变量的参数:
      •  
      • ★★★ 使用 set 命令查看已经定义的所有变量:
      • ★★★ 使用 unset 来删除变量:
      • ★★★ 使用 set - - 清空位置变量:
      • ★★★ 使用 “”(双引号)来保证变量内容的格式!
      •  
      • ★★★ Linux下设置环境变量:
        • ☆ 为什么要设置环境变量?
      • 用户级别环境变量定义文件:
        • ① 使用 export PATH ==(仅对当前用户和当前终端有效)==
        • ② vim ~/.bashrc ==(仅对当前用户永久生效)==
        • ③ vim ~/.profile ==(仅对当前用户永久有效)==
      • 系统级别环境变量定义文件:
        • ① vim /etc/bashrc ==(对所有用户永久生效)==
        • ② vim /etc/profile ==(对所有用户永久有效)==
        • ③ vim /etc/environment ==(对所有用户永久有效)==
        •  
        • Linux 中系统登录时环境变量加载顺序解析:

 


 

变量?

        顾名思义,变量变量就是可以变化的量!当然这是一句废话!

举例:
        当我们想使用内存空间中的字符串“aaa”的时候,那么在内存空间中就有一个这个字符串“aaa”的地址,在计算机里,存放数据都为二进制格式“010101…”,对于计算机来说,使用“010101…”这个地址很简单,但是对于我们用户来说,那么多字符串的地址我们怎么可以记得住,为了方便就使用变量!

格式:     值类型 varname=“值”(静态语言)
                或
                varname=“值”(动态语言)

 


 

变量的赋值:

       

①、静态语言 或 强类型

        在使用变量的时候,必须声明 变量的类型
        eg: C++、java…

int varname=100;

int 大家都知道是指定 "整数类型" 的一个 "函数"

②、动态语言 或 弱类型

        在使用变量的时候,不需要声明 变量的类型 变量的类型一般就是被赋值的那个值的类型!
        eg:Python、PHP、shell…

varname=100;

100是整数,所以这里 varname 的类型就为 int

 


 

变量名命名规则?

①、不建议使用程序中的保留字:例如 if、for…

root@zhengzelin:~# type if
if is a shell keyword(关键字)

"可以使用,但是不建议使用。"

②、只能使用数字、字母、下划线,不能使用数字开头

root@zhengzelin:~# n1=aaa  (√)

root@zhengzelin:~# 1n=aaa  (×)
1n=aaa: command not found

root@zhengzelin:~# n?=aaa  (×)
n?=aaa: command not found

③、驼峰命名法

在命名变量名的时候,每个人的格式不一样;假如定义一个变量名为 my name ,
可能出现的格式:myname、my_name、MyName或者myName。

这样的命名规则不适合所有程序员阅读,而利用驼峰命名法来表示,可以增加程序可读性。例如:

"大驼峰" —— 所有单词的首字母都大写:       myname  = MyName
"小驼峰" —— 第一个单子首字母小写,后续大写:myname =myName

如果你的上头要求用什么格式写就按什么格式写,没要求就按 “驼峰命名法”

 

bash 中 变量的种类:

 
注意:这里说到了是 shell 中的 bash shell ,其他的shell有一点细微区别!
 

①、局部变量:

        顾名思义,就是局部范围内有效只在 当前shell进程 生效(包括其子进程都不生效)。

        同理:在子shell创建的变量 ,在父shell 里也不生效!

 

★ 如何使用局部变量?
a=1   #这就是一个局部变量,最为简单,直接赋值即可!
★ 如何证明局部变量的生效范围?
①、首先 使用 set 命令查看所有变量:
首先,在当前shell 创建一个变量:
root@zhengzelin:~# a=1
root@zhengzelin:~# echo $a
1
root@zhengzelin:~# set | grep "^a"
a=1
②、接着 使用 bash 命令 进入当前shell 的子shell 进程:
# bash 命令是在后台执行,并不影响其他命令的使用。

root@zhengzelin:~# echo $$   # 查看当前 shell进程 的 PID23905
root@zhengzelin:~# bash      # 再次打开一个shell进程,也就是当前shell进程的子进程
root@zhengzelin:~# echo $$   # 查看当前 shell进程 的 PID23921
root@zhengzelin:~# echo $PPID   # 查看当前shell进程的父shell进程的PID
23905

之前的 变量a 是在当前 shell进程 的父进程内命名的,
在当前shell 中查看 之前的变量 a 是否存在:
root@zhengzelin:~# set | grep ^a
[]
"发现此时的 变量a 不复存在!证明了局部变量的范围!"

如何返回当前子shell进程 的父进程? 下面会使用:
③、然后 使用 pstree -p 来查看进程之间的树状关系图:
root@zhengzelin:~# echo $$      # 本 shell 的进程
23921
root@zhengzelin:~# echo $PPID    # 父shell的进程
23905

root@zhengzelin:~# pstree -p 
systemd(1) |........(省略...)
           ├─sshd(963)───sshd(23887)───bash(23905)───bash(23921)───pstree(23936)

可以很清楚的看见: 2390523921 的关系。

   
④、最后 使用 exit 命令退出当前 shell进程:
返回当前 shell 进程 的父shell进程:

root@zhengzelin:~# echo $PPID
23905
root@zhengzelin:~# echo $$
23921
root@zhengzelin:~# exit
exit
root@zhengzelin:~# echo $$
23905

再次查看之前的变量a
root@zhengzelin:~# set | grep ^a
a=1

 


②、全局变量(环境变量):

        生效范围 为 当前shell进程 及其 子shell 进程。

 

★ 常用的全局变量列表:
变量名 作用 用法
PATH 定义了 运行命令的查找路径 echo $PATH
HOME 显示当前用户所在的家目录 同上
LANG 显示当前的系统语言 同上
SHELL 显示当前的 shell类型 同上
SHLVL 显示当前shell进程的嵌套深度 同上
USER 显示当前的 username 同上
HISTSIZE 输出的历史命令记录条数 同上
HISTFILESIZE 显示 保存的历史命令记录条数 同上
PS1 系统登录提示符(#、$) +1

eg:使用 SHLVL 变量:

root@zhengzelin:~# echo $SHLVL     # 查看当前嵌套的shell进程
1      
root@zhengzelin:~# bash    # 进入子shell 进程
root@zhengzelin:~# echo $SHLVL
2

题外话:history 保存的历史命令存在 "~/.bash_history 中",属于存在硬盘上!
★ 使用关键字 export 来定义全局变量:
"要想定义全局变量,必须使用一个关键字": export 

这里的步骤和原理 与 上面测试局部变量生效范围 的原理是一样的;
就不做一一解释了:

root@zhengzelin:~# echo $$
23905
root@zhengzelin:~# export name=1   # 定义全局变量
root@zhengzelin:~# bash
root@zhengzelin:~# echo $$
24158
root@zhengzelin:~# echo $PPID
23905
root@zhengzelin:~# echo $name
1
root@zhengzelin:~# exit
exit

由此可以证明 全局变量的生效范围:当前shell进程及其子shell进程都生效!
那么在 子 shell 中创建的 全局变量,父 shell 里还可以生效吗:

root@zhengzelin:~# echo $$     
24252
root@zhengzelin:~# bash       
root@zhengzelin:~# export b=111  
root@zhengzelin:~# env | grep ^b
b=111
root@zhengzelin:~# echo $$
24267
root@zhengzelin:~# echo $PPID
24252
root@zhengzelin:~# exit
exit
root@zhengzelin:~# echo $$
24252
root@zhengzelin:~# echo $b
[]


"只能父进程传给子进程,子进程不能传给父进程!"
★ 使用 “declare -x” 定义全局变量:
这里就不做解释了,自己可以动手敲一敲!
★ 使用 export 来查看所有环境变量:
当你使用 export ,后面不加变量名的时候,这就代表查看所有环境变量:
root@zhengzelin:~# export
.......
declare -x TERM="xterm"
declare -x USER="root"
declare -x a="2"
.......

"为什么前面是 declare -x 呢? 其实使用 “declare -x” 也可以定义全局变量!"

★ 使用 evn 命令 查看所有环境变量
root@zhengzelin:~# env
XDG_SESSION_ID=3906

USER=root
MAIL=/var/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
PWD=/root
LANG=en_US.UTF-8
SHLVL=3
HOME=/root
......

★☆★_注意:局部和全局变量只能父传子,子不能传父!

 

③、特殊变量(系统变量):

★ 系统变量图表:
系统变量 作用
$0 当前脚本的名字
$* 当前脚本的 所有参数(不包括程序本身)
$@ 也是表达所有参数,但是与 $* 有区别,下面会讲
$# 当前脚本的 参数个数(不包括程序本身)
$? 程序或命令执行完的状态,返回值为 0 表示执行成功
$$ 程序本身的 PID
$PPID 当前 shell进程 的 父进程 的 PID 号
★ $* 和 $@ 的区别是什么?

注意:$* 和 $@ 只有被双引号(" ") 引起来的的时候才有区别!( “$*” 和 “$@”)

"①、 $* :传递给脚本的参数,所有参数合并为一个字符串!"
"②、 $@ : 传递给脚本的所有参数,每个参数为独立的字符串!"

直接举例:
root@zhengzelin:~# vim a.sh
#/bin/bash
echo "this is first script's all variable : $*"  # 这里就是显示此脚本的所有位置参数,这里使用 $* 和 $@ 都一样
./b.sh "$*"                                      # 在a脚本里面调用b脚本,b脚本里面去调用"$*" 
                                                   "这里的$* 指的就是 b 脚本的位置变量的参数"

★★★ 注意: 这里的第二个 $* 一定要用""(双引号) 括起来,不然提现不出来他们的区别!
                                                   


查看一下 b脚本 的内容:
root@zhengzelin:~# vim b.sh
#/bin/bash
echo "this is the first variable of the second script: $1"

直接来验证一下结果:
root@zhengzelin:~# ./a.sh  a b c
this is first script's all variable : a b c 
this is the first variable of the second script: a b c 

(b脚本本来的位置变量是 $1,按照正常的结果来看应该输出的是"a" 啊,这里为什么是"a b c" 呢?)
(这就是上面提到的: $* 是将"传递给脚本的所有参数合并为一个参数!")
既然都合为一个参数了,所以 "$1" 指的就是 "a b c"


那么我们来验证 "$@" : 将脚本a的 "$*" 换为 "$@":
root@zhengzelin:~# cat a.sh 
#/bin/bash
echo "this is first script's variable : $*"
./b.sh "$@"    ———— # 只需要更换这个参数即可,这个是用来传递参数给另一个脚本的!

"来看一下执行结果:"
root@zhengzelin:~# ./a.sh  a b c
this is first script's all variable : a b c
this is the first variable of the second script: a

       

④、只读变量:

        顾名思义,就是该变量只能读,不可以修改 和 删除!除非你结束程序它会自动消失。
       

★ 如何声明只读变量:
readonly varname=value
或
declare r varname=value

declare -x varname=value # 这个是声明全局变量!
★ 如何查看只读变量:
"readonly -p"

root@zhengzelin:~# readonly -p
declare -r BASHOPTS="checkwinsize:cmdhist:complete_fullquote:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath"
declare -ir BASHPID
declare -ar BASH_VERSINFO='([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")'
declare -ir EUID="0"
declare -ir PPID="24748"
declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"
declare -ir UID="0"

 


 

⑤、位置变量:

        位置变量,这个很重要,一般我们写的变量都是写死的,这个位置变量可以使我们的脚本变得更加的灵活!
       

★ 使用   $1…$n 来表示位置变量
$1 : 第一个位置变量..
$2 : 第二个位置变量..
...
★ 简单使用 位置变量 和 系统变量做一个例子:
root@zhengzelin:~#  cat a.sh 
#!/bin/bash
echo `date +%F`
echo -e "\033[1;36m start... \033[0m"
echo "first number is $1"
echo "second number is $2"
echo "all number is $*"
echo "all number‘s number is $#"
echo "this script name is $0"
echo -e "\033[1;36m stop... \033[0m"

然后使用位置变量:当然你可以换为其他数字或字符串
root@zhengzelin:~# ./a.sh 1 2
2020-03-20
 start... 
first number is 1
second number is 2
all number is 1 2
all number‘s number is 2
this script name is ./a.sh
 stop... 

这里发现 $0 表达1脚本名字会带路径 ./a.sh 
"然后可以使用 basename 来取消路径,只显示文件名:"

root@zhengzelin:~# cat a.sh
.......
echo "this script name is `basename $0`" (注意反撇号)
root@zhengzelin:~# ./a.sh 
.....
this script name is a.sh (对比上面的输出结果发现路径没有了)
.....
★ 用 $10 等十位数作为位置变量的时候,使用 { } !
首先看一下脚本内容:
root@zhengzelin:~# cat a.sh 
#!/bin/bash
echo `date +%F`; echo -e "\033[1;36m start... \033[0m"
echo "first number is $9"
echo "second number is $10"    ———— 重要的 $10 在这里!
echo "all number is $*"
echo "all number‘s number is $#"
echo "this script name is `basename $0`"
echo -e "\033[1;36m stop... \033[0m"


root@zhengzelin:~# ./a.sh a b c d e f g h i j k
2020-03-21
 start... 
first number is i
second number is a0    —————— 但是你发现这里的输出结果是 a0?为什么是a0呢?
                              a在上面表示的位置是 $1,所以系统将 $10分为$1+0
                              所以这边的输出结果就为 : $10 = a0
                             
避免这种情况的话就使用 "{ }" 将位置变量括起来:
${10}   我这就不演示了
★ 使用 shift 往前移动位置变量的参数:
仅执行 shift ,代表往前移动一位位置变量的参数!
移动两位的话就是: shift 2

eg:
root@zhengzelin:~# cat b.sh 
#/bin/bash
echo "the first variable is : $1"
echo "the second variable is : $2"
shift
echo "the third variable is :$3"
root@zhengzelin:~# ./b.sh 1 2 3 4 5
the first variable is : 1
the second variable is : 2
the third variable is :4     #执行了 shift 之后,原来3就被跳过了

当你将原来的 shift 变为 shift 2 的时候,$3就变成了数组 5

 


 

★★★ 使用 set 命令查看已经定义的所有变量:

记得是所有变量:局部变量 + 全局变量

查看全局: export 或 declare -x 或 env

★★★ 使用 unset 来删除变量:

"格式: unset varname ,不需要加 $符号!"

root@zhengzelin:~# export a=111
root@zhengzelin:~# unset $a | echo $?
1
-bash: unset: `1': not a valid identifier

root@zhengzelin:~# unset a | echo $?
0

"结合特殊变量 “$?” 来查看结果"

★★★ 使用 set - - 清空位置变量:

root@zhengzelin:~# cat b.sh 
#/bin/bash
echo "the first variable is : $1"
echo "the second variable is : $2"
echo "the third variable is :$3"

root@zhengzelin:~# ./b.sh a b c
the first variable is : a
the second variable is : b
the third variable is :c


正常结果就是以上输出的结果,现在使用 "set --" 来清空下面的位置变量!
root@zhengzelin:~# cat b.sh 
#/bin/bash
echo "the first variable is : $1"
set --
echo "the second variable is : $2"
echo "the third variable is :$3"

root@zhengzelin:~# ./b.sh a b c
the first variable is : a
the second variable is : 
the third variable is :

★★★ 使用 “”(双引号)来保证变量内容的格式!

当你的变量是一个文件或者一段有格式的内容的时候,如果你使用简单的 $varnmae 
你会发现 当你 echo 它的时候,输出的结果为一段话,把多行内容合并在一起了!
eg:
root@zhengzelin:~# VarName=`cat /etc/fstab`
root@zhengzelin:~# echo $VarName
# /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # <file system> <mount point> <type> <options> <dump> <pass> # / was on /dev/vda1 during installation 

"这个时候就可以使用双引号了:"
root@zhengzelin:~# echo "$VarName"
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/vda1 during installation
.....

 

★★★ Linux下设置环境变量:

 

☆ 为什么要设置环境变量?

        当你自定义安装一个软件的时候,当安装完成之后,你需要使用命令来对此软件执行操作,如果你没有设置环境变量的话,你就不能直接使用此命令!

        举例,假如你安装了 mysql,当你要使用 mysql 命令的时候,你发现你不能直接使用,除非你使用特定的格式才能执行命令(eg:/安装路径/…/mysql/bin),否则系统会提示没有此命令,这就是因为你没有设置 PATH 环境变量,此 环境变量的作用就是:系统会从 PATH环境变量里找执行那个命令的路径,如果这些路径里没有mysql命令,当然不能执行了!所以你就得使用命令 给他添加到 PATH环境变量里了!具体添加方法下面有介绍!
 


用户级别环境变量定义文件:

① 使用 export PATH (仅对当前用户和当前终端有效)

生效时间: "立即生效"
生效范围: "仅仅对当前shell进程 和 当前用户生效" ,关闭当前shell即失效!
格式 :export  PATH=$PATH:/新的路径

root@zhengzelin:~# export PATH=$PATH:/tmp/zzl
root@zhengzelin:~# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/tmp/zzl

② vim ~/.bashrc (仅对当前用户永久生效)

# ubuntu 和 centos 中 文件名一样!

生效时间: 使用 "当前用户打开新的终端的时候生效"
          或  
          使用 "source  ~/.bashrc"  手动立即生效
       
格式:"vim  ~/.bashrc"

# 在最后一行加上 export PATH=$PATH/tmp/zzl

添加了环境变量之后,可以使用"source 命令"来使你的配置文件立即生效

"source ~/.bashrc"

③ vim ~/.profile (仅对当前用户永久有效)

Centos中: ~/.bash_profile
Ubuntu中: ~/.profile

# 和修改 ~/.bashrc 文件类似,也是在文件末添加新路径即可

# 使用同一个用户打开一个新的终端生效,或者 "source" 一下生效!

系统级别环境变量定义文件:

① vim /etc/bashrc (对所有用户永久生效)

# 该方法是修改系统配置、需要 root 权限!
Centos 中: /etc/bashrc
Ubuntu 中: /etc/bash.bashrc

root@zhengzelin:~# vim /etc/bash.bashrc 
# 在最后一行加上 : export PATH=$PATH:/new

生效方式: "source  位置即可"
root@zhengzelin:~# source /etc/bash.bashrc 

注意:如果 该文件不可编辑,需要改为可编辑!权限问题咯!

② vim /etc/profile (对所有用户永久有效)

# Centos 和 Ubuntu 中 配置文件名字一样!
方法与上面的 "/etc/bashrc" 类似。

需要 root 权限,手动 source 生效,

③ vim /etc/environment (对所有用户永久有效)

# 放法 及 权限 与 修改 /etc/profile 一样!

 

Linux 中系统登录时环境变量加载顺序解析:

 
本篇文件写的太长了,切换下一个文章来写吧!望理解!

戳我去学习 跟 登录Linux有关的环境变量配置文件 的加载过程
戳我去学习 跟 登录Linux无关的环境变量配置文件 的加载过程

你可能感兴趣的:(shell)