배열 항목 대신 완전 배열 개체를 한 번에 하나씩 파이프로 연결하시겠습니까?
한 CmdLet의 출력을 어레이의 개별 항목이 아닌 전체 어레이 개체로 파이프라인의 다음 CmdLet로 어떻게 전송합니까?
-인 설명 - 일반적인 설명
about_pipelines에 대한 도움말에서 볼 수 있는 것처럼)help pipeline
powershell은 한 번에 하나씩 객체를 파이프라인 아래로 보냅니다.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
?
각주
- 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
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
'programing' 카테고리의 다른 글
다른 뷰에서 뷰 작성 (0) | 2023.07.28 |
---|---|
도커 컨테이너 및 mysql 워크벤치 내의 MariaDb에 대한 연결 (0) | 2023.07.28 |
Oracle 시간대가 있는 TIMESTAMP를 DATE로 변환 (0) | 2023.07.28 |
Python 요청 라이브러리 새 URL 리디렉션 (0) | 2023.07.23 |
SQLite에서 Oracle INSTR 교체 (0) | 2023.07.23 |