Bash의 프로세스 대체와 동등한 Powershell


14

Bash는 <(..)프로세스 대체 를 위해 존재합니다. Powershell과 동등한 기능은 무엇입니까?

나는 $(...)있지만 문자열을 반환하지만 <(..)외부 명령이 읽을 수있는 파일 을 반환합니다.

파이프 기반 솔루션을 찾고 있지 않지만 명령 줄 중간에 붙일 수있는 것을 찾고 있습니다.


3
afaik 그런 것은 없지만 잘못된 것으로 판명되는 것은 흥미로울 것입니다.
Zoredache

4
당신이 그것을 어떻게 사용할 지에 대한 모형을 보여줄 수 있습니까? $ (... | select -expandproperty objectyouwanttopass)가 단일 대체 사례에 적합한 지 궁금합니다.
Andy

2
PowerShell에서 $ ()는 하위 표현식 연산자이므로 다음과 같이 사용할 수 있습니다 Write-Output "The BITS service is $(Get-Service bits | select -ExpandProperty Stauts)". 변수에 먼저로드하지 않고 BITS 서비스의 상태를 가져옵니다. 프로세스 대체를 살펴보면 이것은 정확히 같지는 않지만 여전히 직면하고있는 문제를 해결할 수 있습니다.
mortenya

@Andy :이 기능은 파일 이름 피연산자 가 필요한 외부 유틸리티에 도움이됩니다 . SFTP 전송 의 예는 다음과 같습니다. 옵션을 사용하려면 파일을 통해 서버에서 실행할 명령을 제공해야합니다 . 예를 들어 , 실행하려는 경우 불편 합니다. PowerShell에서 프로세스를 대체 한 경우 다음과 같은 작업을 수행 할 수 있습니다. psftp.exe-bmget *psftp.exe -l user -p password somehost -b <( "mget *" )
mklement

답변:


4

이 대답은 당신을 위해 NOT 다음과 같은 경우,
거의 어느 경우 필요 외부 경기 선행 지수를 사용하지 않으려면 (대한 가치 분투가 일반적이다 - - PowerShell을 네이티브 명령은 훨씬 더 함께 플레이와 같은 기능에 대한 필요가 없습니다).
-Bash의 프로세스 대체에 익숙하지 않습니다.
이 답변 은 다음 과 같은 경우에 도움이됩니다.-
특히 스크립트를 작성하는 동안 외부 CLI를 사용합니다 (습관이 없는지 또는 PowerShell 고유의 대안이 없는지에 따라).
-Bash의 프로세스 대체가 할 수있는 일을 이해하고 이해하는 데 사용됩니다.
- 업데이트 : 이제 Unix 플랫폼에서도 PowerShell이 ​​지원 되므로이 기능 에 대한 관심이 높아지고 있습니다. GitHub에서이 기능 요청을 참조하십시오.이는 PowerShell이 ​​대체를 처리하는 것과 유사한 기능을 구현할 것을 제안합니다.

유닉스 세계에서 Bash / Ksh / Zsh에서 프로세스 대체 는 명령 출력을 마치 자체적으로 정리 되는 임시 파일 인 것처럼 처리 합니다. 예를 들어 cat <(echo 'hello'), 여기서 명령의 출력을 명령 출력을 포함 하는 임시 파일경로cat봅니다 .echo

PowerShell 기본 명령에는 이러한 기능이 실제로 필요하지 않지만 외부 CLI를 처리 할 때 유용 할 수 있습니다 .

PowerShell에서 기능을 에뮬레이트하는 것은 번거롭지 만 자주 필요한 경우 유용 할 수 있습니다.

cf스크립트 블록을 받아들이고 블록을 실행하고 출력을 temp에 기록하는 명명 된 함수를 그림으로 만듭니다. 파일은 요청시 생성되며 임시를 반환합니다. 파일의 경로 ; 예 :

 findstr.exe "Windows" (cf { Get-ChildItem c:\ }) # findstr sees the temp. file's path.

이것은 그러한 기능 의 필요성 을 잘 설명하지 않는 간단한 예입니다 . 아마도보다 설득력있는 시나리오는 psftp.exeSFTP 전송을 사용하는 것입니다 . 배치 (자동화)를 사용하려면 원하는 명령이 포함 된 입력 파일 을 제공해야 하지만 이러한 명령은 즉시 문자열로 쉽게 만들 수 있습니다.

가능한 한 외부 유틸리티와 광범위하게 호환되도록 임시. 필요한 경우 파일을 사용 하여 UTF-8 BOM을 요청할 수 있지만 파일은 기본적으로 BOM (바이트 순서 표시) 없이 UTF-8 인코딩 -BOM 사용해야합니다.

불행히도, 프로세스 대체 의 자동 정리 측면을 직접 에뮬레이트 할 수 없으므로 명시적인 정리 호출이 필요합니다 . 정리는 cf 인수없이 호출하여 수행됩니다 .

  • 에 대한 대화 형 사용, 당신은 할 수 있습니다 당신에 정리 호출을 추가하여 정리를 자동화 prompt(다음과 같은 기능 prompt기능 프롬프트 반환 문자열을 뿐만 아니라 막후을 수행 할 수 있습니다 배쉬의 유사한 메시지가 표시 될 때마다, 명령 $PROMPT_COMMAND변하기 쉬운); 대화 형 세션에서 사용 가능 cf하도록하려면 PowerShell 프로필 에 다음 정의와 아래 정의를 추가하십시오 .

    "function prompt { cf 4>`$null; $((get-item function:prompt).definition) }" |
      Invoke-Expression
  • 스크립트 에서 사용하려면 정리가 수행되도록하려면 cf잠재적으로 전체 스크립트 를 사용하는 블록을 try/ finally블록 으로 묶어야하며, cf인수없이 정리가 호출됩니다.

# Example
try {

  # Pass the output from `Get-ChildItem` via a temporary file.
  findstr.exe "Windows" (cf { Get-ChildItem c:\ })

  # cf() will reuse the existing temp. file for additional invocations.
  # Invoking it without parameters will delete the temp. file.

} finally {
  cf  # Clean up the temp. file.
}

구현 은 다음과 같습니다 . 고급 함수 ConvertTo-TempFile및 간결한 별명 cf:

참고 : 동적 모듈New-Module통해 함수를 정의하기 위해 PSv3 +가 필요한을 사용 하면 함수 매개 변수와 전달 된 스크립트 블록 내부에서 참조되는 변수간에 변수 충돌이 발생하지 않습니다.

$null = New-Module {  # Load as dynamic module
  # Define a succinct alias.
  set-alias cf ConvertTo-TempFile
  function ConvertTo-TempFile {
    [CmdletBinding(DefaultParameterSetName='Cleanup')]
    param(
        [Parameter(ParameterSetName='Standard', Mandatory=$true, Position=0)]
        [ScriptBlock] $ScriptBlock
      , [Parameter(ParameterSetName='Standard', Position=1)]
        [string] $LiteralPath
      , [Parameter(ParameterSetName='Standard')]
        [string] $Extension
      , [Parameter(ParameterSetName='Standard')]
        [switch] $BOM
    )

    $prevFilePath = Test-Path variable:__cttfFilePath
    if ($PSCmdlet.ParameterSetName -eq 'Cleanup') {
      if ($prevFilePath) { 
        Write-Verbose "Removing temp. file: $__cttfFilePath"
        Remove-Item -ErrorAction SilentlyContinue $__cttfFilePath
        Remove-Variable -Scope Script  __cttfFilePath
      } else {
        Write-Verbose "Nothing to clean up."
      }
    } else { # script block specified
      if ($Extension -and $Extension -notlike '.*') { $Extension = ".$Extension" }
      if ($LiteralPath) {
        # Since we'll be using a .NET framework classes directly, 
        # we must sync .NET's notion of the current dir. with PowerShell's.
        [Environment]::CurrentDirectory = $pwd
        if ([System.IO.Directory]::Exists($LiteralPath)) { 
          $script:__cttfFilePath = [IO.Path]::Combine($LiteralPath, [IO.Path]::GetRandomFileName() + $Extension)
          Write-Verbose "Creating file with random name in specified folder: '$__cttfFilePath'."
        } else { # presumptive path to a *file* specified
          if (-not [System.IO.Directory]::Exists((Split-Path $LiteralPath))) {
            Throw "Output folder '$(Split-Path $LiteralPath)' must exist."
          }
          $script:__cttfFilePath = $LiteralPath
          Write-Verbose "Using explicitly specified file path: '$__cttfFilePath'."
        }
      } else { # Create temp. file in the user's temporary folder.
        if (-not $prevFilePath) { 
          if ($Extension) {
            $script:__cttfFilePath = [IO.Path]::Combine([IO.Path]::GetTempPath(), [IO.Path]::GetRandomFileName() + $Extension)
          } else {
            $script:__cttfFilePath = [IO.Path]::GetTempFilename() 
          }
          Write-Verbose "Creating temp. file: $__cttfFilePath"
        } else {
          Write-Verbose "Reusing temp. file: $__cttfFilePath"      
        }
      }
      if (-not $BOM) { # UTF8 file *without* BOM
        # Note: Out-File, sadly, doesn't support creating UTF8-encoded files 
        #       *without a BOM*, so we must use the .NET framework.
        #       [IO.StreamWriter] by default writes UTF-8 files without a BOM.
        $sw = New-Object IO.StreamWriter $__cttfFilePath
        try {
            . $ScriptBlock | Out-String -Stream | % { $sw.WriteLine($_) }
        } finally { $sw.Close() }
      } else { # UTF8 file *with* BOM
        . $ScriptBlock | Out-File -Encoding utf8 $__cttfFilePath
      }
      return $__cttfFilePath
    }
  }
}

출력 [file] 경로 및 / 또는 파일 이름 확장자를 선택적으로 지정할 수 있습니다.


이 작업을 수행해야한다는 아이디어는 기껏해야 모호하며 단순히 PowerShell을 사용하고 싶지 않기 때문에 상황을 더욱 어렵게 만듭니다.
Jim B

1
@ JimB : 개인적으로 사용 psftp.exe하여 작성하라는 메시지가 표시됩니다. PowerShell에서 기본적으로 모든 작업을 수행하는 것이 바람직하지만 항상 가능한 것은 아닙니다. PowerShell에서 외부 CLI를 호출하면 계속 발생하고 계속 진행됩니다. 메모리에서 / 더 쉽게 다른 명령으로 구성 할 수있는 파일 입력이 필요한 CLI를 반복적으로 다루는 경우이 답변의 기능으로 인생을 더 쉽게 만들 수 있습니다.
mklement

농담하니? 그 중 어느 것도 필요하지 않습니다. 매개 변수에 대한 명령이있는 파일 만 허용하는 명령을 아직 찾지 못했습니다. SFTP에 관한 한 간단한 검색은 PowerShell에서 기본적으로 FTP를 수행하는 2 개의 간단한 addin 어셈블리를 보여줍니다.
Jim B

1
@JimB :이 대화를 건설적인 방식으로 계속하려면 톤을 변경하십시오.
mklement 2016 년

2
@JimB GNU Diffutils diff는 파일이있는 경우에만 파일에서 작동합니다.
Pavel

2

큰 따옴표로 묶지 않으면 $(...)PowerShell 개체 (또는 코드로 반환 된 모든 항목)를 반환하고 포함 된 코드를 먼저 평가합니다. 이것은 명령 줄이 PowerShell 인 것으로 가정하여 사용자의 목적에 적합해야합니다 ( "명령 줄 중간에 무언가 [I]가 붙어있을 수 있습니다").

다양한 버전을로 파이핑 Get-Member하거나 직접 출력 하여 테스트 할 수 있습니다 .

PS> "$(ls C:\Temp\Files)"
new1.txt new2.txt

PS> $(ls C:\Temp\Files)


    Directory: C:\Temp\Files


Mode                LastWriteTime         Length Name                                                                      
----                -------------         ------ ----                                                                      
-a----       02/06/2015     14:58              0 new1.txt                                                                  
-a----       02/06/2015     14:58              0 new2.txt   

PS> "$(ls C:\Temp\Files)" | gm


   TypeName: System.String
<# snip #>

PS> $(ls C:\Temp\Files) | gm


   TypeName: System.IO.FileInfo
<# snip #>

큰 따옴표로 묶으면` "$ (...)"는 문자열을 반환합니다.

이런 식으로 파일의 내용을 한 줄에 직접 삽입하려면 다음과 같은 것을 사용할 수 있습니다.

Invoke-Command -ComputerName (Get-Content C:\Temp\Files\new1.txt) -ScriptBlock {<# something #>}

이것은 환상적인 답변입니다!
GregL

당신이 묘사 한 것은 Bash의 프로세스 대체와 동일 하지 않습니다 . 프로세스 대체는 파일 이름 피연산자 가 필요한 명령과 함께 사용하도록 설계되었습니다 . 즉, 프로세스 대체에 포함 된 명령의 출력은 느슨하게 말해서 임시 파일에 기록되며 해당 파일의 경로 가 리턴됩니다. 또한 파일의 존재 범위는 프로세스 대체가 포함 된 명령의 범위입니다. PowerShell에 이러한 기능이있는 경우 다음과 같은 기능이 필요합니다.Get-Content <(Get-ChildItem)
mklement

내가 틀렸다면 나를 수정하십시오. 이것은 당신이 찾고있는 것이 아니지만 Get-ChildItem | Get-Content완벽하게 작동 하지 않습니까? 아니면 Get-Content (Get-ChildItem).FullName같은 효과를 시도해 볼 수 있습니까? 다른 스크립팅 방식의 영향을받는 관점에서이 방식에 접근하고있을 수 있습니다.
James Ruskin

1
예, PowerShell 영역 에서는이 기능이 필요하지 않습니다. 파일 입력 이 필요한 외부 CLI 에만 사용되며 이러한 파일의 내용이 (PowerShell) 명령으로 쉽게 구성되는 경우 에만 유용 합니다. 실제 사례에 대한 질문에 대한 내 의견을 참조하십시오. 당신은 이러한 기능이 필요 없지만, 자주는 관심의 외부 경기 선행 지수를 호출 할 필요가 사람들을위한 않을 수도 있습니다. OP가 구체적으로 요청한 것과는 달리 PowerShell 이 작업을 수행하는 방식과 그 이유 를 시연한다고 말함으로써 최소한 답변의 머리말 을 작성해야합니다 .
mklement
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.