• Shell 局部变量
  • Shell 全局变量
    • shell全局变量的易错点
    • linux shell中./a.sh , sh a.sh , source a.sh, . ./a.sh的区别
  • Shell 环境变量
    • shell配置文件

Shell 变量的作用域(Scope),就是 Shell 变量的有效范围(可以使用的范围)。Shell 变量的作用域可以分为三种:
  1.有的变量只能在函数内部使用,这叫做局部变量(local variable)
  2.有的变量可以在当前 Shell 进程中使用,这叫做全局变量(global variable)
  3.有的变量可以在子进程中使用,这叫做环境变量(environment variable)

Shell 局部变量

原理
代码
 
结论

shell函数中定义的变量为全局变量,与在函数外部定义变量的效果一样

#!/bin/bash 

function func(){
  a=99
}
func   #调用函数
echo $a #输出函数内部的变量
99 #输出结果

a 是在函数内部定义的,但是在函数外部也可以得到它的值,

证明它的作用域是全局的,而不是仅限于函数内部

要想变量的作用域仅限于函数内部

可以在定义时加上local命令,此时该变量就成了局部变量

#!/bin/bash

function func(){
  local a=99
func    #调用函数
echo $a #输出函数内部的变量
输出结果为空

输出结果为空,表明变量 a 在函数外部无效,是一个局部变量

Shell 变量的这个特性和 JavaScript 中的变量是类似的。

在 JavaScript 函数内部定义的变量,默认也是全局变量,

只有加上var关键字,它才会变成局部变量。

Shell 全局变量

在 Shell 中定义的变量,默认就是全局变量,该变量在当前的整个 Shell 进程中都有效。
需要强调的是,全局变量的作用范围是当前的 Shell 进程,而不仅仅是当前的 Shell 脚本文件,它们是不同的概念。打开一个 Shell 窗口就创建了一个 Shell 进程,打开多个 Shell 窗口就创建了多个 Shell 进程,每个 Shell 进程都是独立的,拥有不同的进程 ID。在一个 Shell 进程中可以使用 source 命令执行多个 Shell 脚本文件,此时全局变量在这些脚本文件中都有效。

关注点 操作 对比1 对比2 其他
全局变量的作用范围是当前shell进程 打开两个shell窗口,验证变量作用域

打开一个 Shell 窗口,定义一个变量 b 并赋值为 88,然后打印,这时在同一个 Shell 窗口中是可正确打印变量 b 的值的。

再打开一个新的 Shell 窗口,同样打印变量 b 的值,但结果却为空。

 
全局变量的作用范围是不仅仅在当前的 Shell 脚本文件 在当前shell窗口定义变量a,可以被脚本1使用,在脚本1中定义的变量b,可以在脚本2中使用

a.sh

  1. #!/bin/bash
  2. echo $a
  3. b=200

b.sh

  1. #!/bin/bash
  2. echo $b

这三条命令都是在一个进程中执行的,从输出结果可以发现,在 Shell 窗口中以命令行的形式定义的变量 a,在 a.sh 中有效;

在 a.sh 中定义的变量 b,在 b.sh 中也有效,变量 b 的作用范围已经超越了 a.sh。

在Shell 窗口,输入以下命令

a=99

. ./a.sh -->99

在同样的shell中执行. ./b.sh -->200

shell全局变量的易错点:

脚本
分析
PARAM_NUMBER=0;
cat "/home/roaddb/test/55.txt" | while read line
do
let PARAM_NUMBER=${PARAM_NUMBER}+1;
done
echo "${PARAM_NUMBER}"
结果PARAM_NUMBER的值还是0,原因是在进行 cat的过程中, 相当于打开了一个新的shell,变量不在作用范围。
#!/bin/bash
PARAM_NUMBER=0;
while read line
do
let PARAM_NUMBER=${PARAM_NUMBER}+1;
done<"/home/roaddb/test/55.txt"
echo "${PARAM_NUMBER}"
PARAM_NUMBER的值是正确的

linux shell中./a.sh , sh a.sh , source a.sh, . ./a.sh的区别

脚本 知识点  
#! /bin/bash
echo "PID of this script: $$"
echo "PPID of this script: $PPID"

echo $$  输出当前进程号-------->590
echo $PPID 输出父进程号-------->589

 
执行方式 结果  
a.sh

报错bash: a.sh: command not found

 

./a.sh

bash: ./a.sh: Permission denied

需要权限,设置权限为777后执行

PID of this script: 92669
PPID of this script: 590

启了一个子shell来执行a.sh,

所以可以看到PPID of this script: 590

sh ./a.sh 

PID of this script: 92878
PPID of this script: 590

sh a.sh 

PID of this script: 92928
PPID of this script: 590

source ./a.sh 

PID of this script: 590
PPID of this script: 589

在当前shell中执行脚本
source a.sh 

PID of this script: 590
PPID of this script: 589

. ./a.sh

两个点之间有空格

PID of this script: 590
PPID of this script: 589

../a.sh

报错bash: ../a.sh: No such file or directory

 

最后要说明的两点是:

  1. 用sh和source去执行时, 不要求a.sh有可执行权限, 但单独./a.sh这样去搞时,需要可执行权限
  2. 大家在开发项目时,经常需要设置环境变量, 当然是用source啊, 确保在当前shell生效

Shell 环境变量

全局变量只在当前 Shell 进程中有效,对其它 Shell 进程和子进程都无效。如果使用export命令将全局变量导出,那么它就在所有的子进程中也有效了,这称为“环境变量”
环境变量被创建时所处的 Shell 进程称为父进程,如果在父进程中再创建一个新的进程来执行 Shell 命令,那么这个新的进程被称作 Shell 子进程。当 Shell 子进程产生时,它会继承父进程的环境变量为自己所用,所以说环境变量可从父进程传给子进程或者孙进程。
注意,两个没有父子关系的 Shell 进程是不能传递环境变量的,并且环境变量只能向下传递而不能向上传递,即“传子不传父”。

使用env可以查看所有环境变量!!!
创建 Shell 子进程最简单的方式是运行 bash 命令,如图所示。

通过exit命令可以一层一层地退出 Shell。

下面演示一下环境变量的使用:

[c.biancheng.net]$ a=22       #定义一个全局变量
[c.biancheng.net]$ echo $a #在当前Shell中输出a,成功
22
[c.biancheng.net]$ bash #进入Shell子进程
[c.biancheng.net]$ echo $a #在子进程中输出a,失败 [c.biancheng.net]$ exit #退出Shell子进程,返回上一级Shell
exit
[c.biancheng.net]$ export a #将a导出为环境变量
[c.biancheng.net]$ bash #重新进入Shell子进程
[c.biancheng.net]$ echo $a #在子进程中再次输出a,成功
22
[c.biancheng.net]$ exit #退出Shell子进程
exit
[c.biancheng.net]$ exit #退出父进程,结束整个Shell会话

环境变量也是临时的,通过 export 导出的环境变量只对当前 Shell 进程以及所有的子进程有效,如果最顶层的父进程被关闭了,那么环境变量也就随之消失了,其它的进程也就无法使用了,所以说环境变量也是临时的。

shell配置文件

那如何让一个变量在所有 Shell 进程中都有效,不管它们之间是否存在父子关系呢?只有将变量写入 Shell 配置文件中才能达到这个目的!Shell 进程每次启动时都会执行配置文件中的代码做一些初始化工作,如果将变量放在配置文件中,那么每次启动进程都会定义这个变量。

1)shell 配置文件的加载

无论是否是交互式,是否是登录式,Bash Shell 在启动时总要配置其运行环境,例如初始化环境变量、设置命令提示符、指定系统命令路径等。这个过程是通过加载一系列配置文件完成的,这些配置文件其实就是 Shell 脚本文件。
与 Bash Shell 有关的配置文件主要有 /etc/profile、~/.bash_profile、~/.bash_login、~/.profile、~/.bashrc、/etc/bashrc、/etc/profile.d/*.sh,不同的启动方式会加载不同的配置文件。

~表示用户主目录。*是通配符,/etc/profile.d/*.sh 表示 /etc/profile.d/ 目录下所有的脚本文件(以.sh结尾的文件)。

登录式的 Shell

如果是登录式的 Shell,首先会读取和执行 /etc/profiles,这是所有用户的全局配置文件,接着会到用户主目录中寻找 ~/.bash_profile、~/.bash_login 或者 ~/.profile,它们都是用户个人的配置文件
不同的 Linux 发行版附带的个人配置文件也不同,有的可能只有其中一个,有的可能三者都有。如果三个文件同时存在时,它们的优先级顺序是 ~/.bash_profile > ~/.bash_login > ~/.profile。

如果 ~/.bash_profile 存在,那么一切以该文件为准,并且到此结束,不再加载其它的配置文件。
如果 ~/.bash_profile 不存在,那么尝试加载 ~/.bash_login。~/.bash_login 存在的话就到此结束,不存在的话就加载 ~/.profile。

~/.bash_profile 中会加载 ~/.bashrc:

if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

非登录的 Shell

如果以非登录的方式启动 Shell,那么就不会读取以上所说的配置文件,而是直接读取 ~/.bashrc。

~/.bashrc 文件还会嵌套加载 /etc/bashrc,请看下面的代码:

if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi

1shell变量的作用域的更多相关文章

  1. js学习之变量、作用域和内存问题

    js学习之变量.作用域和内存问题 标签(空格分隔): javascript 变量 1.基本类型和引用类型: 基本类型值:Undefined, Null, Boolean, Number, String ...

  2. 深入理解 JavaScript 变量的作用域和作用域链

    一个变量的作用域(scope)是程序源代码中定义这个变量的区域.简单的说,作用域就是变量与函数的可访问范围.全局变量拥有全局作用域,在JavaScript代码中的任何地方都有定义.局部变量是在函数体内 ...

  3. js变量及其作用域(附例子及讲解)

    Javascript和Java.C这些语言不同,它是一种无类型.弱检测的语言.它对变量的定义并不需要声明变量类型,我们只要通过赋值的形式,可以将各种类型的数据赋值给同一个变量   工具/原料   Ch ...

  4. javascript变量的作用域

    javascript变量的作用域 基本类型和引用类型 基本类型值指的是简单的数据段,而引用类型值指的是那个可能由多个值组成的对象  讲一个值赋值给变量时,javascript解析器首先要确定是基本类型 ...

  5. Js中变量的作用域

    一.理解函数作用域需要理解以下几点:    1.函数变量的作用域有全局变量和局部变量两种,全局变量写在函数的最前面,局部变量写在函数体内,局部变量省略了var 也就默认成为了全局变量!    2.函数 ...

  6. 《征服 C 指针》摘录2:C变量的 作用域 和 生命周期(存储期)

    在开发一些小程序的时候,也许我们并不在意作用域的必要性.可是,当你书写几万行,甚至几十万行的代码的时候,没有作用域肯定是不能忍受的. C 语言有如下 3 种作用域. 1.全局变量 在函数之外声明的变量 ...

  7. JavaScript变量和作用域

    认识JavaScript中的变量 JavaScript中的变量有两种类型,一种是基本类型.一种是引用类型. 基本数据类型:Defined,Null,Boolean,Number,String.注意St ...

  8. JavaScript笔记:变量及其作用域

    一.变量的定义及声明 在javascript中变量仅仅是用来保存值的一个占位符而已,定义变量时要使用关键字var后跟一个变量名,如下所示: var message; //定义一个变量message,像 ...

  9. JavaScript变量的作用域和函数的作用域的区别

    变量作用域和函数作用域都涉及到变量值的变化,本文旨在让大家明白他们之间的区别 变量的作用域: 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接 ...

随机推荐

  1. JDK、JRE 和 JVM 的区别

    JDK JDK 是 Java Development Kit 的缩写,JDK 是 Java 语言的软件开发工具包( SDK ).它提供了Java 开发.编译.运行需要的文件和环境. 如果你是 Java ...

  2. C语言编程 菜鸟练习100题(51-60)

    [练习51]矩阵转置 0. 题目: 矩阵的转置 1. 分析: 练习使用 for 循环嵌套,多维数组的表达. 2. 程序: #include <stdio.h> int main() { i ...

  3. ffmpeg安装之mac安装

    转发自白狼栈:查看原文 关于ffmpeg的安装,有的人可能要折腾很久,甚至折腾一个礼拜,究其原因,基本都是编译安装惹的祸. 我们提供4种安装方式,最复杂的莫过于centos7上的编译安装. ffmpe ...

  4. systemverilog数组类型

  5. 西门子 S7-200 通过以太网通讯模块连接MCGS 通讯

    北京华科远创科技有限研发的远创智控ETH-YC模块,以太网通讯模块型号有MPI-ETH-YC01和PPI-ETH-YC01,适用于西门子S7-200/S7-300/S7-400.SMART S7-20 ...

  6. [leetcode] 90. 子集 II.md

    90. 子集 II 78. 子集题的扩展,其中的元素可能会出现重复了 我们仍沿用78题的代码,稍作改动即可: 此时需要对nums先排个序,方便我们后面跳过选取相同的子集. 跳过选取相同的子集.当选取完 ...

  7. go语言json技巧

    go语言json技巧 本文总结了在项目中遇到的那些关于go语言JSON数据与结构体之间相互转换的问题及解决办法. 基本的序列化 首先我们来看一下Go语言中json.Marshal()(系列化)与jso ...

  8. Go语言协程并发---读写锁sync.RWMutex

    package main import ( "fmt" "sync" "time" ) /* 读写锁 多路只读 一路只写 读写互斥 */ / ...

  9. TVM自定义数据类型

    TVM自定义数据类型 本文将介绍"自定义数据类型"框架,该框架可在TVM中使用自定义数据类型. 介绍 在设计加速器时,关键是如何近似地表示硬件中的实数.这个问题具有长期的行业标准解 ...

  10. Yolov3&Yolov4网络结构与源码分析

    Yolov3&Yolov4网络结构与源码分析 从2018年Yolov3年提出的两年后,在原作者声名放弃更新Yolo算法后,俄罗斯的Alexey大神扛起了Yolov4的大旗. 文章目录 1. 论 ...