programing

PowerShell의 가변 범위 지정

powerit 2023. 9. 25. 23:08
반응형

PowerShell의 가변 범위 지정

PowerShell의 아쉬운 점은 기능과 스크립트 블록이 동적으로 범위를 지정한다는 것입니다.

하지만 저를 놀라게 한 또 다른 점은 변수가 내부 범위 내에서 복사-온-라이트(copy-on-write) 역할을 한다는 것입니다.

$array=@("g")
function foo()
{
    $array += "h"
    Write-Host $array
}

& {
    $array +="s"
    Write-Host $array
}
foo

Write-Host $array

출력은 다음과 같습니다.

g s
g h
g

그래서 역동적인 스코프가 조금 덜 고통스럽습니다.하지만 어떻게 하면 복사-온-라이트를 피할 수 있을까요?

PowerShell scope 기사(_Scopes 관련)는 훌륭하지만 너무 장황하기 때문에 제 기사에서 인용한 내용은 다음과 같습니다.

일반적으로 PowerShell 스코프는 다음과 같습니다.NET 스코프.다음과 같습니다.

  • 전역 공개
  • 스크립트가 내부에 있습니다.
  • 비공개
  • 로컬이 현재 스택 수준입니다.
  • 번호가 매겨진 스코프가 0입니다.N(각 단계가 스택 레벨까지이고 0은 로컬)

스코프의 용도와 효과를 설명하는 간단한 예는 다음과 같습니다.

$test = 'Global Scope'
Function Foo {
    $test = 'Function Scope'
    Write-Host $Global:test                                  # Global Scope
    Write-Host $Local:test                                   # Function Scope
    Write-Host $test                                         # Function Scope
    Write-Host (Get-Variable -Name test -ValueOnly -Scope 0) # Function Scope
    Write-Host (Get-Variable -Name test -ValueOnly -Scope 1) # Global Scope
}
Foo

보시다시피 $Global:test는 명명된 스코프에서만 구문처럼 사용할 수 있으며 $0:test는 항상 $null입니다.

스코프 수정자를 사용하거나*-Variablecmdlet

스코프 수정자는 다음과 같습니다.

  • global 셸에서 y하는 데근됨예:셸)
  • script 중인 스됩니다().ps1을(를) 일)로합니다. 스크립트를 실행하지 않으면 다음과 같이 작동합니다.global.

)-Scope*-Variable cmdlets see help.

에서 전역 를 하려면, $array:

& {
  $global:array +="s"
  Write-Host $array
}

자세한 내용은 _scope에 대한 도움말 항목을 참조하십시오.

변수만이 아닙니다.이것이 "item"이라고 말하는 것은 변수, 함수, 별칭 및 psdrive를 의미합니다.그것들은 모두 범위를 가지고 있습니다.

긴 설명Windows PowerShell은 변수, 별칭, 기능 및Windows PowerShell 드라이브(PSD)는 읽기 및 읽기 가능한 위치를 제한하여변경되었다.범위에 대한 몇 가지 간단한 규칙을 적용하여 Windows PowerShell을(를) 사용하여 실수로 변경하지 않도록 합니다.변하지 않습니다.

범위의 기본 규칙은 다음과 같습니다.
- 범위에 포함하는 항목은 해당 항목이 있는 범위에 표시됩니다.명시적으로 만들지 않는 한 모든 하위 범위에서 생성되었습니다.사적인.변수, 별칭, 함수 또는 Windows를 배치할 수 있습니다.PowerShell 드라이브를 하나 이상의 범위에 배치합니다.
- 범위 내에서 생성한 항목은 에서만 변경할 수 있습니다.명시적으로 지정하지 않는 한, 작성된 범위범위가 다른

지금 보시는 쓰기 문제의 복사본은 파워셸이 배열을 처리하는 방식 때문입니다.해당 배열에 추가하면 원래 배열이 실제로 파괴되고 새 배열이 생성됩니다.해당 스코프에서 생성되었기 때문에 함수 또는 스크립트 블록이 종료되고 스코프가 폐기되면 삭제됩니다.

변수를 업데이트할 때 명시적으로 범위를 지정하거나 [ref] 개체를 사용하여 업데이트하거나 스크립트를 작성하여 개체의 속성이나 개체의 해시 테이블 키 또는 상위 범위의 해시 테이블 키를 업데이트할 수 있습니다.이렇게 하면 로컬 범위에 새 개체가 생성되지 않고 상위 범위에 있는 개체가 수정됩니다.

다른 게시물들은 많은 유용한 정보를 제공하지만 RTFM으로부터 당신을 구하는 것처럼 보입니다.
언급되지 않은 답은 내가 가장 유용하다고 생각하는 것입니다!

([ref]$var).value = 'x'

이렇게 하면 $var 값이 어떤 범위에 있든 상관없이 변경됩니다.당신은 그 범위를 알 필요는 없습니다. 단지 그것이 실제로 이미 존재한다는 것 뿐입니다.OP의 예를 사용하려면:

$array=@("g")
function foo()
{
    ([ref]$array).Value += "h"
    Write-Host $array
}
& {
    ([ref]$array).Value +="s"
    Write-Host $array
}
foo
Write-Host $array

제작물:

g s
g s h
g s h

설명:
([ref]$var)는 변수에 대한 포인터를 가져옵니다.읽기 작업이므로 실제로 해당 이름을 만든 가장 최근의 범위로 해결됩니다.또한 [ref]가 아무것도 생성할 수 없기 때문에 변수가 존재하지 않는 경우에는 이미 존재하는 것에 대한 참조만 반환할 수 있습니다.

그런 다음 .value를 선택하면 변수의 정의를 저장하는 속성으로 이동합니다. 그런 다음 변수 정의를 설정할 수 있습니다.

때로는 효과가 있는 것처럼 보이기 때문에 여러분은 이와 같은 일을 하고 싶은 유혹을 받을 수도 있습니다.

([ref]$var) = "New Value"

하지마!!!!
PowerShell이 명령줄과 같은 매우 좁은 환경에서만 수행하는 작업이기 때문에 작동하는 것처럼 보이는 경우는 환상에 불과합니다.믿을 수 없습니다.사실 OP 예제에서는 작동하지 않습니다.

PowerShell의 아쉬운 점은 기능과 스크립트 블록이 동적으로 범위를 지정한다는 것입니다.

.GetNewClosure()를 사용하여 즉시 로컬 범위에서 변수를 캡처하는 클로저를 만듭니다.

function New-Closure
{
    $foo = 42
    {$foo}.GetNewClosure()
}

❯ $Closure = New-Closure
❯ & $Closure
# output: 42

스코프는 다음 모듈 속성을 통해 액세스할 수 있습니다.

❯ {"some new scriptblock"}.Module
# no output

❯ $Closure.Module

ModuleType Version    PreRelease Name                                ExportedCommands
---------- -------    ---------- ----                                ----------------
Script     0.0                   __DynamicModule_f89a39f6-f9f7-40ce…

함수도 동적 범위가 되어야 하는지 여부는 언어 설계 결정입니다.함수가 호출자의 범위에서 동적 변수에 액세스할 수 없도록 허용하는 스크립트 언어를 생각할 수 없습니다. - 아마도 당신은 Haskell ;-)에서 자랐을 것입니다.

편집: 함수는 포함된 모듈의 범위에 접근할 수 있습니다.파워셸 전개 단위는 모듈입니다.모듈을 작성하지 않으려면 동적 모듈을 생성할 수 있습니다.

New-Module {
    $foo = 23
    function Get-EnclosedFoo
    {
        $foo
    }
}
# output: dynamic module

Get-EnclosedFoo
# output: 23

언급URL : https://stackoverflow.com/questions/9325569/variable-scoping-in-powershell

반응형