如何将控制台输出直接管道传输到记事本?


47

我正在命令提示符或Git Shell 上运行应用程序,我想将输出输出到记事本中,以便以后进行查看和编辑。

我尝试了以下操作,但是我总是得到一个空的记事本实例:

diff file1.txt file2.txt | notepad

我知道我可以将输出重定向到另一个文件,然后在记事本中打开该文件。我想避免多余的步骤,因为我只是习惯于在非Windows系统上管道传输到Vim或更少版本。


2
当然,您也可以more在Windows上通过管道进行连接。
加布2014年

1
为什么不通过管道传输文件并仅通过shell执行新文件路径-让OS处理演示应用程序。它一定是记事本吗?
Gusdor 2014年

@Gusdor问题主要是关于避免创建(临时)文件。
Der Hochstapler 2014年

1
记事本的功能是如此有限,以至于您几乎无法执行任何操作。既然您熟悉vim,为什么不直接安装它呢?
思远任

@CR我可以在自己的计算机上执行此操作,但是我经常在不属于自己的计算机上工作。因此,在不安装第三方软件的情况下了解存在哪些选项会很有帮助。
Der Hochstapler 2014年

Answers:


63

据我所知,无法直接通过管道传递到记事本中。

但是,您可以通过管道将clip粘贴然后粘贴到记事本中,如下所示:

 diff file1.txt file2.txt | clip && notepad

然后只需在记事本中按Ctrl+ V


3
如果将输出重定向到file3.txt,然后它会工作&& notepad file3.txt吗?
Konerak 2014年

4
@Konerak是的,那会起作用,而这正是我要避免的问题(如问题中所述);)
Der Hochstapler 2014年

32

考虑使用Vim,或者如果您更喜欢图形环境,则考虑使用gVim。

然后,您可以使用单个连字符作为参数将其插入其中,指示Vim / gVim从标准输入中读取。

diff file1.txt file2.txt | gvim -

1
安装它,记事本真的很有限,您不能为此使用它。你甚至可以把它在便携式应用:portableapps.com/apps/development/gvim_portable
伊基塔

3
也可以在vim中执行此操作::%!diff file1.txt file2.txt
SlightlyCuban 2014年

@TankorSmash我也可以,但这不是问题的重点;)有关vim(或任何其他主题)的进一步利弊讨论,请在“ 超级用户聊天”中找到我,注释主题不是进行对话的好方法:(
Der Hochstapler 2014年

1
@OliverSalzburg我试图建议Windows上可以使用gvim,因为我理解您的评论意味着没有。我错了。
TankorSmash 2014年

-经常用来表示“从stdin读取”,因此并不严格限于vim。其他编辑器使用-i(例如kate)。
Bakuriu 2014年

8

是一个简短的Windows程序,可以正确执行此操作(不破坏剪贴板)。它应该适用于PowerShell,如果时间允许,我可能会更新此答案,但是您也可以直接使用该程序。

好吧,PowerShell呢?无需安装其他应用程序。不幸的是,您需要在PATH...中的某个位置创建脚本文件。

您可以使用的短版

如果您创建ShowInNotepad.bat具有以下内容的批处理文件(例如)并将其放在您的PATH某个位置:

@echo off
clip
powershell -Command $process = Start-Process -PassThru notepad;$SW_SHOW = 5;$sig = '[DllImport("""user32.dll""")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);';Add-Type -MemberDefinition $sig -name NativeMethods -namespace Win32;[Win32.NativeMethods]::ShowWindow($process.Id, $SW_SHOW) ^| Out-Null;Add-Type -AssemblyName System.Windows.Forms;[System.Windows.Forms.SendKeys]::SendWait('^^V');

然后,您可以echo blah | ShowInNotepad从任何地方打电话!

请注意,这确实是假设您使用的是Windows的最新版本(Vista +),并且没有禁用PowerShell或卸载.NET框架。换句话说,将使用默认的Windows安装。


冗长的解释和替代方法

我能想到的最简单的方法是使粘贴(Ctrl+ V)操作自动化。至少有另一个答案已经在做,但是那个答案正在使用AHK-您可能会更幸运地让PowerShell在锁定的公司环境中工作。

让我们继续脚本吧?

#start notepad, get process object (to get pid later)
$process = Start-Process -PassThru notepad;

# activate Notepad window
# based on http://stackoverflow.com/a/4994020/1030702
# SW_SHOW activates and shows a window http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548%28v=vs.85%29.aspx
$SW_SHOW = 5;
$sig = '[DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);';
Add-Type -MemberDefinition $sig -name NativeMethods -namespace Win32;
[Win32.NativeMethods]::ShowWindow($process.Id, $SW_SHOW) | Out-Null;

# send a "Ctrl+V" keystroke to the active window
# from http://stackoverflow.com/a/17851491/1030702
Add-Type -AssemblyName System.Windows.Forms;
[System.Windows.Forms.SendKeys]::SendWait('^V');

这非常简单,因此我将比注释早已花更多时间解释脚本。

用法

要使用它,您只需要将脚本放置在.ps1文件中(例如ShowInNotepad.ps1),将其放置在您的文件中的某个位置PATH,然后powershell ShowInNotepad.ps1在将要显示的文本放置在剪贴板中后调用即可。

例:

echo blah | clip && powershell ShowInNotepad.ps1

不幸的是,执行PowerShell脚本有时可能很困难(执行策略和全部)。因此,我已经将此脚本浓缩为一个直线,您可以直接从命令提示符处调用它,甚至可以将其放入批处理文件中:

powershell -Command $process = Start-Process -PassThru notepad;$SW_SHOW = 5;$sig = '[DllImport("""user32.dll""")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);';Add-Type -MemberDefinition $sig -name NativeMethods -namespace Win32;[Win32.NativeMethods]::ShowWindow($process.Id, $SW_SHOW) ^| Out-Null;Add-Type -AssemblyName System.Windows.Forms;[System.Windows.Forms.SendKeys]::SendWait('^^V');

如果您创建ShowInNotepad.bat具有以下内容的批处理文件(例如)并将其放在您的PATH某个位置:

@echo off
clip
powershell -Command $process = Start-Process -PassThru notepad;$SW_SHOW = 5;$sig = '[DllImport("""user32.dll""")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);';Add-Type -MemberDefinition $sig -name NativeMethods -namespace Win32;[Win32.NativeMethods]::ShowWindow($process.Id, $SW_SHOW) ^| Out-Null;Add-Type -AssemblyName System.Windows.Forms;[System.Windows.Forms.SendKeys]::SendWait('^^V');

然后,您可以echo blah | ShowInNotepad从任何地方打电话!


老实说,如果您要编写PS脚本,我只会在temp文件夹中创建一个带有Guid名称的文件,并在完成后将其删除。自动化粘贴操作似乎太脆弱了(例如,如果您在错误的时间失去了注意力会怎样?)?
Casey 2014年

@emodendroket不幸的是,当您试图将流输入强制到本身不支持它的程序中时,没有什么是真正干净的。创建临时文件有其自身的(次要)缺点:您实际上没有得到“新文件”,因此Save修改行为​​上的和退出是不同的。除了替换记事本本身或直接将文本注入其编辑控件外,没有太多其他选择。当然,此方法的缺点是破坏剪贴板内容(尽管无论如何这些内容都是短暂的)。我认为失去重点并不是主要问题;这是一个...
Bob

...极不可能的竞争状态(在ShowWindow和发送击键之间)。而且,此方法确实需要更多设置(创建脚本文件)才能使用。
鲍勃

5

如何使用AutoHotkey

将以下内容另存为stdin.ahk,并将其放在您的AutoHotkey目录中:

StdIn(max_chars=0xfff)
{
    static hStdIn=-1
    ; The following is for vanilla compatibility
    ptrtype := (A_PtrSize = 8) ? "ptr" : "uint"

    if (hStdIn = -1)
    {
        hStdIn := DllCall("GetStdHandle", "UInt", -10,  ptrtype) ; -10=STD_INPUT_HANDLE
        if ErrorLevel
            return 0
    }

    max_chars := VarSetCapacity(text, max_chars*(!!A_IsUnicode+1), 0)

    ret := DllCall("ReadFile"
        ,  ptrtype, hStdIn        ; hFile
        ,  "Str", text          ; lpBuffer
        , "UInt", max_chars*(!!A_IsUnicode+1)     ; nNumberOfBytesToRead
        , "UInt*", bytesRead    ; lpNumberOfBytesRead
        ,  ptrtype, 0)            ; lpOverlapped

    return text
}

loop 
{
    sleep 100 ;wait for data
    Buffer:=StdIn()
    PipeText:=PipeText . Buffer
    IfWinActive Untitled - Notepad
        {
        SendInput {Raw}%PipeText%
        PipeText = 
        }
}

然后在命令行中:

ping -t www.google.com | AutoHotkeyA32.exe stdin.ahk

只要窗口处于打开状态且标题为,就将命令的输出通过管道传递到记事本中Untitled - Notepad。如果该窗口不处于活动状态,则它将愉快地在后台缓冲,直到该窗口处于活动状态。您甚至可以转到另一个程序,它将再次进行缓冲。

但是,当程序输出到我们的标准输入时,它似乎死了……

(有关信息,stdin()代码距离这里几乎是半英寸)


...哇。如果要达到这个程度,不妨编写一个完整的编译程序!也许也可能更有效率:P尽心尽力。
鲍勃

我怕我拒绝投票。古典意义上的过度工程。谁在控制该脚本的版本?autohotkey是否需要商业应用许可?谁来监视?
Gusdor 2014年

7
@Gusdor整个Internet充满了非版本控制的代码片段。我们甚至可以拥有该帖子的修订历史记录。我也看不到商业许可与这个问题有什么关系?AHK被很多人使用,他们可能会觉得此答案有用。
slhck

@slhck我只是在评论此解决方案的缺陷,而不是其有效性。
Gusdor 2014年

@slhck:此网站上的内容已包含在知识共享中。
布莱恩(Brian

4

这是完全可能的。我刚试过 我假设记事本默认设置为打开txt文件:

diff file1.txt file2.txt > output.txt && start output.txt && timeout /T 3 && del output.txt

好的,您实际上是在创建文件,但是不会保存它。

也可以选择更多。


4
小心-如果您已经有一个output.txt将破坏它。使用会更加安全%temp%/somerandomstring.txt
2014年

将输出文件保存在temp目录中更安全-查看答案。
Lu55

1

这是一种丑陋但有效的方法:

$OutputString = 'Hello World'
$WScript = New-Object -ComObject 'wscript.shell'
$WScript.Run('notepad.exe') | Out-Null
do 
    {
    Start-Sleep -Milliseconds 100
    }
until ($WScript.AppActivate('notepad'))
$WScript.SendKeys($OutputString)

只要确保只发送文本输出即可。其他数据可能会解释为控制字符(CTRL,ALT,DEL等)。


0

这是一些可行的基于VBScript的解决方案(尽管它们在某种程度上依赖于按时打开的应用程序):

pipe2key.vbs-打开指定为第一个参数的应用程序,然后将StdIn作为击键发送给它。需要与cscript.exe一起使用,因为wscript不提供StdIn访问。对于长文档来说可能很慢-但是不会破坏剪贴板

Set inPipe=wScript.StdIn
Set wShell=wScript.CreateObject("wscript.shell")
wShell.Run wScript.Arguments(0), 5 ' Execute specified app, foreground it's window
wScript.Sleep 500 ' Wait for app to load
KeysToEscape="{}[]()^+%"
KeysToDrop=vbLf
While Not inPipe.AtEndOfStream
    keyChar=inPipe.Read(1)
    If InStr(KeysToDrop, keyChar) = 0 Then
        If InStr(KeysToEscape, keyChar) > 0 Then
            wShell.SendKeys "{" & keyChar & "}"
        Else
            wShell.SendKeys keyChar
        End If
    End If
Wend

用法示例: diff file1.txt file2.txt | cscript pipe2key.vbs notepad.exe

或者,pasteinto.vbs。启动应用程序后自动执行CTRL-V操作(因此使用前面的答案中提到的'clip'命令)。(我认为)比pipe2key.vbs更快和更干净,但是该过程将覆盖剪贴板

Set wShell=wScript.CreateObject("wscript.shell")
wShell.Run wScript.Arguments(0), 5 ' Execute specified app, foreground it's window
wScript.Sleep 500 ' Wait for app to load
wShell.SendKeys "^v"

用法示例: diff file1.txt file2.txt | clip && pasteinto notepad.exe


-1

像这种“可能”的工作。

w,您没意识到这是您每次都要手动执行的操作(从声音上看)。每次您都可以制作某种宏或执行某种操作来加快处理速度。不确定那一个。

diff file1.txt file2.txt > file.txt | sleep 1 | notepad.exe file.txt | rm file.txt

它必须完成将diff内容写入file.txt的操作,才能加载整个diff操作,但我不确定是否可以。在这种情况下,可能会有某种方式可以在管道操作之间暂停。


5
目标是创建临时文件,我很确定那里的语法有问题;)
Der Hochstapler 2014年

“为了以后进行更轻松的查看和编辑”,我想这就是您想要的?并且正如Rev1.0指出和修改的那样,它可以工作。这是针对dos的,但是我不确定cygwin是否会有相同的结果。
Codezilla 2014年

3
我猜因为一个&就足够了,因为实际上在这些调用之间不需要“管道传输”。
Rev1.0

3
@ Rev1.0正确。&&&并且||是将命令链接在一起的运算符。如果命令生成非零返回值,则这三个函数的行为方式将有所不同。|是完全不同的,因为它是用于输出从一个程序到另一个。结果可能是您想要的,但是使用链接运算符之一可以使意图更清晰,因为在该示例中不需要实际的管道。有关更多参考:microsoft.com/resources/documentation/windows/xp/all/proddocs/...
明镜Hochstapler

1
@Codezilla我认为我帖子中的想法与您的想法非常相似,但是它是有效的命令提示符语法。
Casey

-3

我的语言不是英语,所以很抱歉犯错。

我认为您不能直接将输出放到打开的记事本中。可能是我错了。您必须创建一个包含输出的文件才能对其进行处理。命令tee可以将输出通过管道传输到两个或同时是多个命令或文件。

三通

将输出重新封装到文件中时,不要忘记使用>>代替>。>将覆盖文件,>>将在文件中已有的内容之后添加输出。


1
tee通常在Windows上不可用,即使可以使用,也无济于事。
Der Hochstapler 2014年

-4

您不能,记事本太有限了!更好的是...安装Cygwin并解决Windows的所有“功能不足”问题。然后,您可以使用已经知道的命令。

AFAIK,很少有Windows程序支持管道传输,对于GUI程序则更糟。

您可以尝试向“ Windows tail”程序之一打开功能请求以添加该功能。


2
我已经在使用cygwin。这确实是与记事本交互所特有的问题。
Der Hochstapler 2014年


1
@emodendroket有时人们会使用错误的工具来工作...几乎在任何情况下,记事本都是错误的工具,是如此简单且受限制:)
higuita

1
@higuita我是Emacs专用用户,但有时记事本是我想要做的更好的工具。
Casey 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.