Powershell所有的变量都有一个决定变量是否可用的作用域。Powershell支持四个作用域:全局、当前、私有和脚本。有了这些作用域就可以限制变量的可见性了,尤其是在函数和脚本中。
如果我们对变量不做特别的声明,Powershell解释器会自动处理和限制变量的作用域。将下面的内容命令保存着至test1.ps1
$windows = $env:windir
“Windows Folder: $windows”
然后在控制台给变量$windows赋值,并调用Test.ps1脚本。
PS> $windows="Hellow" PS> .\test.ps1 Windows Folder: C:\Windows PS> $windows Hellow
调用脚本时,会分配一个变量$windows,在脚本调用结束后,这个变量被回收,脚本中的变量不会影响脚本外的变量,因为它们在不同的作用域中。powershell会针对每个函数和脚本给它们分配不同的作用域。
更改变量的可见性
你可以很容易的看到没有Powershell解释器自动限制可见性时会发生什么状况,同样是刚才的脚本,刚才的命令,只是在运行脚本时多加上一个点”.” 和一个空格:
PS> $windows="Hellow" PS> . .\test.ps1 Windows Folder: C:\Windows PS> $windows C:Windows
在运行脚本时使用一个原点和空格,Powershell解释器就不会为脚本本身创建自己的变量作用域,它会共享当前控制台的作用域,这种不太灵活但却简单的方法,使用时一定要格外小心。
加强变量可见性限制的优点:清空初始化环境
可以假设一个场景,如果你在当前控制台不小心定义了一个只读的常量,这个常量既不能更新也不能删除,很是麻烦。但是如果你在脚本中操作这个变量就不成问题,因为脚本有自己的作用域。例如,将下面文本保存为test.ps1,并调用没有任何问题:
New-Variable a -value 1 -option Constant "Value: $a"
PS> .\test.ps1 Value: 1 PS> .\test.ps1 Value: 1
但是如果你通过圆点禁用作用域限制,调用test.ps1,就会有异常,因为一个常量不能被创建两次。
PS> . .\test.ps1 Value: 1 PS> . .\test.ps1 New-Variable : A variable with name 'a' already exists. Attest.ps1:1 char:13 + New-Variable <<<< a -value 1 -option Constant + CategoryInfo : ResourceExists: (a:String) [New-Variable], SessionStateException + FullyQualifiedErrorId : VariableAlreadyExists,Microsoft.PowerShell.Commands.NewVariableCommand
所以这种变量的作用域限制可以把变量的冲突降到最小。
设置单个变量的作用域
到目前为止,看到的变量作用域的改变都是全局的,能不能针对某个具体变量的作用域做一些个性化的设置。
$global
全局变量,在所有的作用域中有效,如果你在脚本或者函数中设置了全局变量,即使脚本和函数都运行结束,这个变量也任然有效。
$script
脚本变量,只会在脚本内部有效,包括脚本中的函数,一旦脚本运行结束,这个变量就会被回收。
$private
私有变量,只会在当前作用域有效,不能贯穿到其他作用域。
$local
默认变量,可以省略修饰符,在当前作用域有效,其它作用域只对它有只读权限。
打开Powershell控制台后,Powershell会自动生成一个新的全局作用域。如果增加了函数和脚本,或者特殊的定义,才会生成其它作用域。在当前控制台,只存在一个作用域,通过修饰符访问,其实访问的是同一个变量:
PS> $logo="www.pstips.net" PS> $logo www.pstips.net PS> $private:logo www.pstips.net PS> $script:logo www.pstips.net PS> $private:logo www.pstips.net PS> $global:logo www.pstips.net
当调用一个已定义的函数,Powershell会生成第二个作用域,它可以对调用者的作用域中的变量执行读操作,但是不能执行写操作。
PS> function f(){ "var=$var";$var="function inner";$var } PS> $var="I am in console." PS> $var I am in console. PS> f var=I am in console. function inner PS> $var I am in console.
怎样把当前控制台中的变量保护起来,不让它在函数和脚本中被访问,Private修饰符就派上了用场。
PS> function f(){ "var=$var";$var="function inner";$var } PS> $private:var="i am a private variable in console,other scope can not access me." PS> f var= function inner PS> $private:var i am a private variable in console,other scope can not access me.
对于$private限制的变量能不能在函数中通过$global修改呢?不但不能修改,还会删除当前的$private变量
PS> Function f(){ "var=$var";$global:var=" Try to change variable in function"} PS> $private:var="I am a private variable" PS> $private:var I am a private variable PS> $var I am a private variable PS> f var= PS> $private:var PS> $var PS> PS> $private -eq $null True
但是$local 修饰的变量则可以通过$global在函数内部更改。
PS> Function f(){ "var=$var";$global:var=" Try to change variable in function"} PS> $var="I am a local variable." PS> $var I am a local variable. PS> $private:var I am a local variable. PS> f var=I am a local variable. PS> $var Try to change variable in function PS> $local:var Try to change variable in function
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!
广播: PowerShell 跨作用域更改变量 | PowerShell 中文博客
“全局变量,在所有的作用域中有效。” 这句话如何理解?在程序中多线程执行:this.iss = InitialSessionState.CreateDefault();this.rs = RunspaceFactory.CreateRunspace(this.iss);this.rs.Open();this.powershell = PowerShell.Create();this.powershell.Runspace = rs;生成的多个rs和powershell,他们算几个作用域?如果算作多个$Global在单个下可以重复使用么?如果算作一个,$Global会共享么?
“全局变量,在所有的作用域中有效”,这个指的是:当前会话下的的所有作用域。不能跨会话。有点像.NET中的App Domain。
不是这样,你开两个ise,而不是两个页面A:$Local:hash=@{}$Local:hash[“name”]=2$Local:hash[“name”]=>2B.$Local:hash[“name”]=>2我理解B里面应该是空才对吧
开两个ISE,A中输出为2, B中报错:Cannot index into a null array.
很诡异的问题,后来重启了机器没有再现这个问题。也报出了:Cannot index into a null array.
所以,我怀疑你可能是在一个ISE中开了两个Page,而不是两个独立的ISE。
真不是,我在提问中特意描述:“而不是两个页面”,希望是我头晕眼花搞错了。如果真是bug,应该还会出现!
还是不太明白。我在脚本的前面定义了一个全局变量:$global:goodBuild=$false;然后while(!$goodBuild){GetLatestBuildif($goodBuild){break;}},在GetLatestBuild这个函数里面我有code把$goodBuild设置为true,但是设置完后,执行到while里面的if判断的时候,$goodBuild的值总是为false而不是true。
本地变量会从全局变量继承值,但是本地变量的更改不会影响全局变量,除非显示制定global。可以参考另外一篇文章:PowerShell 3.0+全局变量继承机制更改 :http://www.pstips.net/powershel-3-0-global-variable-changes.html
问题解决了吗?
我觉得你的逻辑应当是这样的:$global:goodBuild=$falsefunction GetLatestBuild { $goodBuild=$ture}while(!$goodBuild){GetLatestBuildif($goodBuild){break;}}然后就是死循环,因为在你的GetLatestBuild中更新的$goodBuild,而不是 $global:goodBuild.解决方案,改成下面这样就好了。$global:goodBuild=$falsefunction GetLatestBuild { $global:goodBuild=$true}while(!$goodBuild){GetLatestBuildif($goodBuild){break;}}
在win 10下测试了下,private变量在函数内通过global貌似可以修改,只不过option由private变为了None
global是会改private的,这是我的支行结果
PS C:\> Function f(){“var=$var”;$global:var=”Try to change”}
PS C:\> $private:var=”I am a private variable”
PS C:\> f
var=
PS C:\> $private:var
Try to change
我觉得你的这篇文章存在大问题,我不知道你是从哪里得出的这个结论。希望你还继续调查一下关于变量作用域的知识。感觉你说的不是很对
并且不要把错误的信息放上去,那样会误导别人对知识的理解。那是相当恐怖的
可能是ps更新了,有一个地方和楼主说的情况不一样了。
即使标注$private,也可以在函数中通过$global修改$var。
我使用的ps版本是ps5。
额,评论无法贴图,所以楼主自己试试吧。。
其他部分没有问题。
PS C:\Users> Function f(){ “var=$var”;$global:var=” Try to change variable in function”}
PS C:\Users> $private:var=”I am a private variable”
PS C:\Users> $private:var
I am a private variable
PS C:\Users> f
var=
PS C:\Users> $private:var
Try to change variable in function
PS C:\Users> $var
Try to change variable in function
PS C:\Users> $private -eq $null
True
PS C:\Users> $private:var -eq $null
False
这个是我运行的结果,global变量是可以修改private变量的
应该是由于ps更新导致的.
另外,`$global`和`$private`应该没有父子关系吧