code

PowerShell의 변수 범위 지정

codestyles 2020. 11. 26. 08:17
반응형

PowerShell의 변수 범위 지정


PowerShell의 슬픈 점은 함수와 스크립트 블록이 동적으로 범위가 지정된다는 것입니다.

그러나 저를 놀라게 한 또 다른 점은 변수가 내부 범위 내에서 쓰기시 복사처럼 작동한다는 것입니다.

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

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

Write-Host $array

출력은 다음과 같습니다.

g s
g h
g

동적 범위 지정이 조금 덜 고통 스럽습니다. 그러나 기록 중 복사를 어떻게 피할 수 있습니까?


범위 수정 자 또는 *-Variablecmdlet을 사용할 수 있습니다 .

범위 수정자는 다음과 같습니다.

  • global 가장 바깥 쪽 범위에서 액세스 / 수정하는 데 사용됨 (예 : 대화 형 쉘)
  • script실행중인 스크립트 ( .ps1파일) 의 범위에서 액세스 / 수정에 사용됩니다 . 스크립트를 실행하지 않으면 global.

( Cmdlet -Scope매개 변수 *-Variable는 도움말을 참조하십시오.)

예 : 두 번째 예에서는 global을 직접 수정합니다 $array.

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

자세한 내용은 도움말 항목 about_scopes를 참조하십시오 .


PowerShell 범위 기사 ( about_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입니다.


단지 변수가 아닙니다. "항목"이라고하면 변수, 함수, 별칭 및 psdrive를 의미합니다. 모두 범위가 있습니다.

긴 설명  
    Windows PowerShell은 변수, 별칭, 함수 및
    Windows PowerShell 드라이브 (PSDrive)는 읽을 수있는 위치를 제한하고
    변경되었습니다. 범위에 대한 몇 가지 간단한 규칙을 적용하여 Windows PowerShell
    실수로 변경해야하는 항목을 변경하지 않도록합니다.
    변경할 수 없습니다.

    다음은 범위의 기본 규칙입니다.

        -범위에 포함 된 항목은 해당 범위에 표시됩니다.
          명시 적으로 만들지 않는 한 모든 하위 범위에서 생성되었습니다.
          은밀한. 변수, 별칭, 함수 또는 Windows를 배치 할 수 있습니다.
          하나 이상의 범위에있는 PowerShell 드라이브.

        -범위 내에서 생성 한 항목은
          명시 적으로 지정하지 않는 한 생성 된 범위
          다른 범위.

당신이보고있는 쓰기 복사 문제는 Powershell이 ​​배열을 처리하는 방식 때문입니다. 해당 배열에 추가하면 실제로 원래 배열이 파괴되고 새 배열이 생성됩니다. 해당 범위에서 생성되었으므로 함수 또는 스크립트 블록이 종료되고 범위가 폐기되면 소멸됩니다.

변수를 업데이트 할 때 명시 적으로 범위를 지정하거나 [ref] 개체를 사용하여 업데이트를 수행하거나, 개체의 속성 또는 개체 또는 해시 테이블의 해시 테이블 키를 업데이트하도록 스크립트를 작성할 수 있습니다. 부모 범위. 이것은 로컬 범위에 새 개체를 만들지 않고 부모 범위의 개체를 수정합니다.


While other posts give lots of useful information they seem only to save you from RTFM.
The answer not mentioned is the one I find most useful!

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

This modifies the value of $var no matter what scope it happens to be in. You need not know its scope; only that it does in fact already exist. To use the OP's example:

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

Produces:

g s
g s h
g s h

Explanation:
([ref]$var) gets you a pointer to the variable. Since this is a read operation it resolves to the most recent scope that actually did create that name. It also explains the error if the variable doesn't exist because [ref] can't create anything, it can only return a reference to something that already exists.

.value then takes you to the property holding the variable's definition; which you can then set.

You may be tempted to do something like this because it sometimes looks like it works.

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

DON'T!!!!
The instances where it looks like it works is an illusion because PowerShell is doing something that it only does under some very narrow circumstances such as on the command line. You can't count on it. In fact it doesn't work in the OP example.

참고URL : https://stackoverflow.com/questions/9325569/variable-scoping-in-powershell

반응형