顾名思义,变量变量就是可以变化的量!当然这是一句废话!
举例:
当我们想使用内存空间中的字符串“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
如果你的上头要求用什么格式写就按什么格式写,没要求就按 “驼峰命名法”
注意:这里说到了是 shell 中的 bash shell ,其他的shell有一点细微区别!
顾名思义,就是局部范围内有效,只在 当前shell进程 生效(包括其子进程都不生效)。
同理:在子shell创建的变量 ,在父shell 里也不生效!
a=1 #这就是一个局部变量,最为简单,直接赋值即可!
首先,在当前shell 创建一个变量:
root@zhengzelin:~# a=1
root@zhengzelin:~# echo $a
1
root@zhengzelin:~# set | grep "^a"
a=1
# bash 命令是在后台执行,并不影响其他命令的使用。
root@zhengzelin:~# echo $$ # 查看当前 shell进程 的 PID号
23905
root@zhengzelin:~# bash # 再次打开一个shell进程,也就是当前shell进程的子进程
root@zhengzelin:~# echo $$ # 查看当前 shell进程 的 PID号
23921
root@zhengzelin:~# echo $PPID # 查看当前shell进程的父shell进程的PID
23905
之前的 变量a 是在当前 shell进程 的父进程内命名的,
在当前shell 中查看 之前的变量 a 是否存在:
root@zhengzelin:~# set | grep ^a
[空]
"发现此时的 变量a 不复存在!证明了局部变量的范围!"
如何返回当前子shell进程 的父进程? 下面会使用:
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)
可以很清楚的看见: 23905 和 23921 的关系。
返回当前 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
这里的步骤和原理 与 上面测试局部变量生效范围 的原理是一样的;
就不做一一解释了:
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
[空]
"只能父进程传给子进程,子进程不能传给父进程!"
这里就不做解释了,自己可以动手敲一敲!
当你使用 export ,后面不加变量名的时候,这就代表查看所有环境变量:
root@zhengzelin:~# export
.......
declare -x TERM="xterm"
declare -x USER="root"
declare -x a="2"
.......
"为什么前面是 declare -x 呢? 其实使用 “declare -x” 也可以定义全局变量!"
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 : 第一个位置变量..
$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 (对比上面的输出结果发现路径没有了)
.....
首先看一下脚本内容:
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 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 !
记得是所有变量:局部变量 + 全局变量
查看全局: export 或 declare -x 或 env
"格式: 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
"结合特殊变量 “$?” 来查看结果"
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
.....
当你自定义安装一个软件的时候,当安装完成之后,你需要使用命令来对此软件执行操作,如果你没有设置环境变量的话,你就不能直接使用此命令!
举例,假如你安装了 mysql,当你要使用 mysql 命令的时候,你发现你不能直接使用,除非你使用特定的格式才能执行命令(eg:/安装路径/…/mysql/bin),否则系统会提示没有此命令,这就是因为你没有设置 PATH 环境变量,此 环境变量的作用就是:系统会从 PATH环境变量里找执行那个命令的路径,如果这些路径里没有mysql命令,当然不能执行了!所以你就得使用命令 给他添加到 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
# ubuntu 和 centos 中 文件名一样!
生效时间: 使用 "当前用户打开新的终端的时候生效"
或
使用 "source ~/.bashrc" 手动立即生效
格式:"vim ~/.bashrc"
# 在最后一行加上 export PATH=$PATH:/tmp/zzl
添加了环境变量之后,可以使用"source 命令"来使你的配置文件立即生效
"source ~/.bashrc"
Centos中: ~/.bash_profile
Ubuntu中: ~/.profile
# 和修改 ~/.bashrc 文件类似,也是在文件末添加新路径即可
# 使用同一个用户打开一个新的终端生效,或者 "source" 一下生效!
# 该方法是修改系统配置、需要 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
注意:如果 该文件不可编辑,需要改为可编辑!权限问题咯!
# Centos 和 Ubuntu 中 配置文件名字一样!
方法与上面的 "/etc/bashrc" 类似。
需要 root 权限,手动 source 生效,
# 放法 及 权限 与 修改 /etc/profile 一样!
本篇文件写的太长了,切换下一个文章来写吧!望理解!
戳我去学习 跟 登录Linux有关的环境变量配置文件 的加载过程
戳我去学习 跟 登录Linux无关的环境变量配置文件 的加载过程