PowerShell封装以将管道输入导入Python脚本

1 投票
1 回答
2097 浏览
提问于 2025-04-17 13:41

我正在尝试写一个小工具,让我可以把命令的输出直接复制到剪贴板。我在Stack Overflow上看了很多相关的回答,但是都没能解决我的问题,因为它们没有涉及到管道,或者没有使用函数,或者直接报错(也可能是我自己搞错了)。所以我放弃了PowerShell,决定用Python来实现。

我创建了一个叫做copyToClipboard.py的Python脚本:

import sys
from Tkinter import Tk

if sys.stdin.isatty() and len(sys.argv) == 1:
  #We're checking for input on stdin and first argument
  sys.exit()

tk = Tk()
tk.withdraw()
tk.clipboard_clear()

if not sys.stdin.isatty():
    #We have data in stdin
    while 1:
        try:
            line = sys.stdin.readline()
        except KeyboardInterrupt:
            break

        if not line:
            break

        tk.clipboard_append(line)
elif len(sys.argv) > 1:
    for line in sys.argv[1]:
      tk.clipboard_append(line)


tk.destroy()

(我还没有完全测试argv[1]的部分,所以那部分可能不太稳定。我主要关注的是从stdin读取,所以重要的部分是sys.stdin。)

这个脚本运行得很好!当我在包含这个脚本的目录下时,我可以执行类似这样的命令:

ls | python copyToClipboard.py

然后ls的内容就神奇地出现在我的剪贴板上。这正是我想要的。

现在的挑战是把这个功能封装成一个PowerShell函数,让它可以接受管道输入,并简单地把这些输入传递给Python脚本。我的目标是能够使用ls | Out-Clipboard,所以我创建了类似这样的代码:

function Out-ClipBoard() {
    Param(
      [Parameter(ValueFromPipeline=$true)]
      [string] $text
    )
    pushd
    cd \My\Profile\PythonScripts
    $text | python copyToClipboard.py
    popd
}

但是这并不奏效。只有一行$text能传递到Python脚本中。

我该如何构建我的PowerShell脚本的包装器,以便它接收到的任何stdin都能直接传递给Python脚本作为stdin呢?

1 个回答

2

首先,在PowerShell中,多行文本其实是一个数组,所以你需要用到一个叫做 [String[]] 的参数。为了帮你解决问题,可以试试使用过程块:

function Out-ClipBoard() {
    Param(
        [Parameter(ValueFromPipeline=$true)]
        [String[]] $Text
    )
    Begin
    {
        #Runs once to initialize function
        pushd
        cd \My\Profile\PythonScripts
        $output = @()
    }
    Process
    {
        #Saves input from pipeline.
        #Runs multiple times if pipelined or 1 time if sent with parameter
        $output += $Text
    }
    End
    {
        #Turns array into single string and pipes. Only runs once
        $output -join "`r`n" | python copyToClipboard.py
        popd
    }
}

我这里没有Python,所以没法测试。要是你需要通过管道传递多个项目(也就是一个数组),就得用过程块来让PowerShell处理这些内容。关于过程块和高级功能的更多信息,可以去 TechNet 看看。

撰写回答