programing

배열 항목 대신 완전 배열 개체를 한 번에 하나씩 파이프로 연결하시겠습니까?

oldcodes 2023. 7. 28. 22:34
반응형

배열 항목 대신 완전 배열 개체를 한 번에 하나씩 파이프로 연결하시겠습니까?

한 CmdLet의 출력을 어레이의 개별 항목이 아닌 전체 어레이 개체로 파이프라인의 다음 CmdLet로 어떻게 전송합니까?

-인 설명 - 일반적인 설명
about_pipelines에 대한 도움말에서 볼 수 있는 것처럼)help pipelinepowershell은 한 번에 하나씩 객체를 파이프라인 아래로 보냅니다.Get-Process -Name notepad | Stop-Process한 번에 하나의 프로세스를 파이프로 보냅니다.

예를 들어 타사 CmdLet(Do-SomeStuff)은 어떤 방식으로도 수정하거나 변경할 수 없습니다.Do-SomeStuff는 문자열 배열을 전달하거나 단일 문자열 개체를 전달하는 경우 다르게 수행됩니다.

입니다. Do-SomeStuff로 될 수 . 대신할 수 있습니다.ForEach-Object,Select-Object,Write-Host 입력을 CmdLet 명령)

이 예에서는 Do-SomeStuff가 배열의 개별 항목을 한 번에 하나씩 처리합니다.

$theArray = @("A", "B", "C")
$theArray | Do-SomeStuff

전체 배열을 Do-SomeStuff에 하나의 객체로 보내고 싶다면 다음과 같은 것을 시도할 수 있습니다.

@($theArray) | Do-SomeStuff

그러나 PowerShell은 새로운 단일 항목 어레이를 "무시"하기 때문에 기대한 결과를 얻지는 못합니다.

를 합니까, "강제"를요?$theArray한 번에 하나씩 컨텐츠 항목이 아닌 하나의 어레이 객체로 파이프에 전달됩니까?


-인 예 - 실천적인 예
다출력과표니다됩시의 입니다.Write-Host배열을 통과한 경우와 배열의 개별 항목을 동시에 하나씩 통과한 경우가 다릅니다.

PS C:\> $theArray = @("A", "B", "C")
PS C:\> Write-Host $theArray
A B C
PS C:\> $theArray | foreach{Write-Host $_}
A
B
C
PS C:\> @($theArray) | foreach{Write-Host $_}
A
B
C

당신은 어떻게 얻습니까?$theArray | foreach{Write-Host $_}와 동일한 결과물을 생산하기 위해Write-Host $theArray?




각주

  1. Powershell에서 파이프라인 처리

일반 문자열 배열입니다.

PS C:\> @("A", "B", "C").GetType().FullName
System.Object[]


Foreach-ObjectForach-Object에된 입니다.

PS C:\> @("A", "B", "C") | foreach{$_.GetType().FullName}
System.String
System.String
System.String

어레이의 각 문자열은 ForEach-Object CmdLet에 의해 한 번에 하나씩 처리됩니다.


배열 배열이며, 여기서 "내부" 배열은 문자열 배열입니다.

PS C:\> @(@("A", "B", "C"), @("D", "E", "F"), @("G", "H", "I")) | foreach{$_.GetType().FullName}
System.Object[]
System.Object[]
System.Object[]

어레이의 각 어레이는 ForEach-Object CmdLet에 의해 한 번에 하나씩 처리되며, 입력의 각 하위 어레이의 내용은 어레이임에도 불구하고 하나의 개체로 처리됩니다.

간단한 답변: 단항 배열 연산자 사용,:

,$theArray | foreach{Write-Host $_}

대답: 한 가지 이해해야 할 것이 있습니다.@()연산자: 내용이 단순한 표현일 뿐인 경우에도 항상 내용을 문으로 해석합니다.다음 코드를 고려하십시오.

$a='A','B','C'
$b=@($a;)
$c=@($b;)

끝 ▁add다▁end를 합니다.;여기서는 PowerShell에서 생략할 수 있습니다.$a는 세 요소의 배열입니다.의 결과는 무엇입니까?$a; 진서술?$a컬렉션이므로 컬렉션을 열거하고 각 개별 항목을 파이프라인으로 전달해야 합니다. 그서결는의 입니다.$a;문은 파이프라인에 작성된 세 가지 요소입니다.@($a;)배열이 세. 그래서 배열이아보세고요개소를원그들, 만듭다니배열을터부로래닌의▁see▁from,다만▁elements.$b는 세 요소의 배열입니다. 방법으로 ㅠㅠㅠㅠㅠ$c는 동일한 세 요소의 배열입니다.그래서 당신이 글을 쓸 때@($collection)사자가어생레고성하복다, 요를사니합의 $collection단일 요소 배열 대신.

쉼표 문자는 데이터를 배열로 만듭니다.파이프라인이 배열을 배열로 처리하도록 하려면 각 배열 요소에서 개별적으로 작동하는 대신 데이터를 괄호로 묶어야 할 수도 있습니다.

이 기능은 배열에 있는 여러 항목의 상태를 평가해야 하는 경우에 유용합니다.

다음 기능 사용

function funTest {
    param (
        [parameter(Position=1, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
        [alias ("Target")]
        [array]$Targets 
        ) # end param
    begin {}
    process {
        $RandomSeed = $( 1..1000 | Get-Random )
        foreach ($Target in $Targets) {
            Write-Host "$RandomSeed - $Target"
            } # next target
        } # end process
    end {}
    } # end function 

다음 예를 생각해 보십시오.

괄호 안에 배열을 묶는 것만으로 함수가 하나의 프로세스 호출에서 값 배열을 처리하는 것을 보장하지 않습니다.이 예에서는 배열의 각 요소에 대한 난수 변화를 확인할 수 있습니다.

PS C:\> @(1,2,3,4,5) | funTest
153 - 1
87 - 2
96 - 3
96 - 4
986 - 5

선행 콤마를 추가하는 것만으로는 함수가 하나의 프로세스 호출에서 값 배열을 처리하는 것을 보장하지 않습니다.이 예에서는 배열의 각 요소에 대한 난수 변화를 확인할 수 있습니다.

PS C:\> , 1,2,3,4,5 | funTest
1000 - 1
84 - 2
813 - 3
156 - 4
928 - 5

선행 쉼표와 괄호 안의 값 배열을 사용하면 각 명령에 대한 함수의 값이 활용되므로 난수가 동일하게 유지되는 것을 볼 수 있습니다.

PS C:\> , @( 1,2,3,4,5) | funTest
883 - 1
883 - 2
883 - 3
883 - 4
883 - 5

여러분의 과정이 기능이라는 것을 개의치 않는다면 구식 해결책이 있습니다.

설정:PSR 원격 연결 없이 다른 시스템에서 다시 빌드할 수 있는 방식으로 배열을 클립보드에 복사하려고 합니다. " " "로 변환되기를 : 따서라 "A", "B" 및는 "C" 함하배열을포문자다로열있니습수변.@("A","B","C") 그대로의 이 아닌...글자 그대로의 배열입니다.

따라서 다음과 같이 구성할 수 있습니다(다른 이유로 최적은 아니지만 계속 주제를 다루십시오).

# Serialize-List

param 
(
    [Parameter(Mandatory, ValueFromPipeline)]
    [string[]]$list
)
    $output = "@(";

    foreach ($element in $list)
    {
        $output += "`"$element`","
    }

    $output = $output.Substring(0, $output.Length - 1)
    $output += ")"
    $output

배열을 매개 변수로 직접 지정할 때 작동합니다.

Serialize-List $list
@("A","B","C")

...하지만 파이프라인을 통과할 때는 그렇지 않습니다.

$list | Serialize-List
@("C")

그러나 시작, 프로세스 및 종료 블록으로 함수를 재팩터링합니다.

# Serialize-List

param 
(
    [Parameter(Mandatory, ValueFromPipeline)]
    [string[]]$list
)

begin
{
    $output = "@(";
}

process
{
    foreach ($element in $list)
    {
        $output += "`"$element`","
    }
}

end
{
    $output = $output.Substring(0, $output.Length - 1)
    $output += ")"
    $output
}

...그러면 원하는 결과물을 얻을 수 있습니다.

Serialize-List $list
@("A","B","C")

$list | Serialize-List
@("A","B","C")

가장 "올바른" 방법은 Write-Output cmdlet을 사용하고 다음을 지정하는 것입니다.-NoEnumerate스위치:

Write-Output $theArray -NoEnumerate | Do-SomeStuff

또한 저자는 다음과 같이 말합니다.

저는 해킹에 더 가까운 두 번째 방법이 있습니다(그리고 저는 이런 해킹을 피하려고 노력합니다).파이프를 연결하기 전에 배열 앞에 쉼표를 둘 수 있습니다.

둘 다 작동하지만 쉼표 연산자를 사용하면 항상 원래 배열을 포함하는 추가 배열이 만들어집니다.Write-Output -NoEnumerate원본 배열을 파이프라인에 한 번에 씁니다.

함수 사용을 통한 구현

쓰기-출력 - 열거 없음

Write-Output 1, 2.2, '3' -NoEnumerate | Get-Member -Name GetType

함수 정의에서 구현

프로세스 블록의 코드를 End 블록에 넣습니다.

function PipelineDemoA {
    param (
        [Parameter(ValueFromPipeline)]
        [String[]]$Value = '.'
    )
    begin {
        Write-Output '----------begin'
        # $valueList = @() # Object[] cannot add objects dynamically
        $valueList = [System.Collections.ArrayList]@()
    }
    process {
        Write-Output 'process'
        $valueList.Add($Value) | Out-Null
    }
    end {
        Write-Output 'end'
        $Value = $PSBoundParameters['Value'] = $valueList
        Write-Output ($Value -join ', ')
    }
}

'A', 'B' |  PipelineDemoA
@() | PipelineDemoA
PipelineDemoA

자동 변수 $input을 사용합니다.

function PipelineDemoB {
    param (
        [Parameter(ValueFromPipeline)]
        [String[]]$Value
    )
    if ($input.Count -gt 0) { $Value = $PSBoundParameters['Value'] = $input }
}

'A', 'B', 'C' | PipelineDemoB

이 메서드에는 두 호출 메서드를 구분할 수 없는 문제가 있습니다.기본값이 있는 매개 변수에는 권장되지 않습니다.

@() | PipelineDemoB
PipelineDemoB

# What will happen?
@() | Get-ChildItem # -Path is @()
Get-ChildItem # -Path is default value '.'

$input 정보

없는 에서.param는 블, $input 변수는 록입니다.ArrayListEnumeratorSimple.

가 있는 에서.param에서 고리그.begin는 블, $input 변수는 록입니다.ArrayList[0].

가 있는 에서.param에서 고리그.process는 블, $input 변수는 록입니다.ArrayList[1].

가 있는 에서.param에서 고리그.end는 블, $input 변수는 록입니다.Object[0].

가 있는 에서.param록블 및없음음begin,process,end는 블, $input 변수는 록입니다.Object[].

function PipelineDemo1 {
    begin {
        Write-Output '----------begin'
        Write-Output "$($input.GetType().Name) / $($input.MoveNext()) / $($input.Current)"
    }
    process {
        Write-Output '----------process'
        Write-Output "$($input.GetType().Name) / $($input.MoveNext()) / $($input.Current)"
    }
    end {
        Write-Output '----------end'
        Write-Output "$($input.GetType().Name) / $($input.MoveNext()) / $($input.Current)"
    }
}

'A', 'B', 'C' | PipelineDemo1 -Z 'Z'

function PipelineDemo2 {
    param (
        [Parameter(ValueFromPipeline)]
        [String[]]$Value,
        [string]$Z
    )
    begin {
        Write-Output '----------begin'
        Write-Output "$($input.GetType().Name) / $($input.Count) / $($input -join ', ')"
    }
    process {
        Write-Output '----------process'
        Write-Output "$($input.GetType().Name) / $($input.Count) / $($input -join ', ')"
    }
    end {
        Write-Output '----------end'
        Write-Output "$($input.GetType().Name) / $($input.Count) / $($input -join ', ')" # $input = Object[0]
    }
}

'A', 'B', 'C' | PipelineDemo2 -Z 'Z'

function PipelineDemo3 {
    param (
        [Parameter(ValueFromPipeline)]
        [String[]]$Value,
        [string]$Z
    )
    Write-Output '----------default'
    Write-Output "$($input.GetType().Name) / $($input.Count) / $($input -join ', ')"
}

'A', 'B', 'C' | PipelineDemo3 -Z 'Z'

function PipelineDemoValue {
    param (
        [string]$Tag,
        [Parameter(ValueFromPipeline)]
        [String[]]$Value = '.'
    )
    
    Write-Output "----------$Tag"
    Write-Output "Value = $($Value -join ', ') / PSValue = $($PSBoundParameters.ContainsKey('Value')) / $($PSBoundParameters['Value'] -join ', ')"
    Write-Output "input = $($input.Count) / $($input -join ', ')"
}

'A', 'B', 'C' | PipelineDemoValue -Tag 1
@() | PipelineDemoValue -Tag 2
$null | PipelineDemoValue -Tag 3
PipelineDemoValue -Value 'A', 'B', 'C' -Tag 4
PipelineDemoValue -Value $null -Tag 5
PipelineDemoValue -Tag 6
$ar="1","2","3"

$ar | foreach { $_ }

언급URL : https://stackoverflow.com/questions/29973212/pipe-complete-array-objects-instead-of-array-items-one-at-a-time

반응형