54

I'm running an application on the command prompt or a Git shell, and I would like to get the output into Notepad, for easier review and editing later on.

I tried the following, but I always get an empty instance of Notepad:

diff file1.txt file2.txt | notepad

I'm aware that I can redirect the output to another file and then open the file in Notepad. I'd like to avoid the extra step, because I'm just used to piping into Vim or less on non-Windows systems.

7
  • 2
    Of course, you can pipe to more on Windows too.
    – Gabe
    Jun 23, 2014 at 20:49
  • 1
    Why not pipe to file and simply shell execute the new file path - let the OS handle the presentation application. Does it have to be notepad?
    – Gusdor
    Jun 24, 2014 at 11:17
  • @Gusdor The question is primarily about avoiding to create a (temporary) file. Jun 24, 2014 at 11:19
  • 1
    Notepad's functionality is so limited that you can barely do anything with it. Since you are familiar with vim, why not just install it?
    – Siyuan Ren
    Jun 25, 2014 at 3:08
  • @C.R. I could do that on my own computers, but I regularly work on computers which I don't own. So it's helpful to know which options there are without installing third-party software. Jun 25, 2014 at 15:52

11 Answers 11

67

From what I can tell, there is no way to directly pipe into Notepad.

However, you can pipe into clip and then paste in notepad, like so:

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

Then just press Ctrl+V in Notepad.

2
  • 3
    Would it work if you'd redirect the output to file3.txt, and then && notepad file3.txt?
    – Konerak
    Jun 24, 2014 at 9:27
  • 4
    @Konerak Yes, that would work and that is exactly what I was trying to avoid (as explained in the question) ;) Jun 24, 2014 at 9:36
33

Consider using Vim, or in your case gVim if you prefer a graphical environment.

You can then pipe into it with a single hyphen as an argument, which instructs Vim/gVim to read from standard input.

diff file1.txt file2.txt | gvim -
5
  • 1
    install it, Notepad is really limited you can't use it for this. you can even have it in portable apps: portableapps.com/apps/development/gvim_portable
    – higuita
    Jun 23, 2014 at 17:21
  • 3
    Can also do this from within vim: :%!diff file1.txt file2.txt Jun 23, 2014 at 17:52
  • @TankorSmash So do I, but that's not the point of the question ;) For further pro and con discussions regarding vim (or any other topic), please find me on Super User Chat, comment threads are not a great way to have a conversation :( Jun 23, 2014 at 18:30
  • 1
    @OliverSalzburg I was trying to suggest that gvim is available on Windows, since I understood your comment to mean that it wasn't. I was wrong. Jun 23, 2014 at 18:35
  • - is often used to mean "read from stdin", so this isn't strictly limited to vim. Other editors use -i (e.g. kate).
    – Bakuriu
    Jun 25, 2014 at 11:37
9

here's a short Windows program that does it properly (without clobbering the clipboard). It should be adaptable to PowerShell, and I might update this answer if I get the time, but you can also just use that program directly.

Well, how about PowerShell? No need to install another application. Unfortunately, you will need to create a script file somewhere in your PATH...

Short version you can use

If you create a batch file (e.g. ShowInNotepad.bat) with the following contents and place it in your PATH somewhere:

@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');

you can then just call echo blah | ShowInNotepad from anywhere!

Note that this does assume that you're using a recent-ish version of Windows (Vista+) and have not disabled PowerShell or uninstalled the .NET framework. In other words, a default Windows installation will work.


Lengthy explanation and alternatives

The easiest way I can think of is to automate the paste (Ctrl+V) action. Which at least one other answer is already doing, but that one uses AHK - you might have better luck getting PowerShell to work in a locked-down corporate environment.

Let's get on with the script, yea?

#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');

It's pretty straightforward, so I won't bother explaining the script more than the comments already do.

Usage

To use it, you just need to place the script in a .ps1 file (e.g. ShowInNotepad.ps1), place it somewhere in your PATH and then call powershell ShowInNotepad.ps1 after placing the text you want to display in the clipboard.

Example:

echo blah | clip && powershell ShowInNotepad.ps1

Unfortunately, executing PowerShell scripts can sometimes be difficult (execution policies and all). Therefore, I've condensed this script to a one-liner you can call directly from the Command Prompt, or even place into a batch file:

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');

If you create a batch file (e.g. ShowInNotepad.bat) with the following contents and place it in your PATH somewhere:

@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');

you can then just call echo blah | ShowInNotepad from anywhere!

3
  • Honestly if you're going to write a PS script I would just create a file with a Guid name in the temp file folder and delete it when I was done. Automating the paste seems too brittle (like what if you lose focus at the wrong time or something)?
    – Casey
    Jun 24, 2014 at 15:21
  • @emodendroket Unfortunately, when you're trying to force stream input into a program that doesn't natively support it, nothing is truly clean. Creating a temp file has its own (minor) drawbacks: you don't actually get a "new file", so the Save and exit on modified behaviours are different. Short of replacing Notepad itself or directly injecting the text into its edit control, there's not many other options. Of course, this method has the drawback of clobbering clipboard contents (though those are supposed to be ephemeral anyway). I don't think losing focus is a major issue; it's an...
    – Bob
    Jun 24, 2014 at 15:27
  • ...extremely unlikely race condition (between the ShowWindow and sending keystrokes). And this method does require a bit more setup (creating the script file) to use, yes.
    – Bob
    Jun 24, 2014 at 15:28
5

How about using AutoHotkey?

Save the following as stdin.ahk and put it in your AutoHotkey directory:

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 = 
        }
}

Then the command line:

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

Pipes the output of the command into Notepad, so long as the window is open and titled Untitled - Notepad. In the event that the window is not active then it will cheerfully buffer in the background until the window is active. You can even go away to another program and it will carry on buffering once more.

This seems to die when the program outputting to our standard input dies though...

(For information, the stdin() code was shamelessly half-inched from here)

5
  • ...wow. If you're going to go to that extent, might as well write a whole compiled program! Probably be more efficient too :P Upvote for the effort though.
    – Bob
    Jun 24, 2014 at 10:59
  • Downvote from me im afraid. Overengineering in the classical sense. Who is version controlling this script? Does autohotkey need a license for commercial applications? Who monitors that?
    – Gusdor
    Jun 24, 2014 at 11:19
  • 7
    @Gusdor The entire Internet is full of non-version controlled code snippets. We have the benefit of even having a revision history for this post. I also don't see how commercial licensing has anything to do with this question? AHK is used by a lot of people, and they might find this answer useful.
    – slhck
    Jun 24, 2014 at 12:21
  • @slhck I was simply remarking on the pitfalls of this solution, not its validity.
    – Gusdor
    Jun 24, 2014 at 12:44
  • @slhck: Content on this site is covered by Creative Commons. Jun 24, 2014 at 20:35
4

This is totally possible; I just tried it. I'm assuming Notepad is set to open txt files by default:

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

OK, you're technically creating a file, but it doesn't get saved.

Piping into more is also an option.

2
  • 4
    Be careful - if you already have an output.txt this will clobber it. Marginally safer would be to use %temp%/somerandomstring.txt.
    – Bob
    Jun 24, 2014 at 11:00
  • It's more safe to save an output file in temp directory - take a look at this answer. Oct 11, 2017 at 19:30
1

Here is an ugly, but effective way to accomplish this:

$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)

Just be sure to only send text output. Other data will potentially be interpreted as control characters (CTRL, ALT, DEL, etc.).

1

Yet another solution to consider! VS Code can receive piped input also, if you now use this instead of Notepad. I noticed this in V1.41, don't know when it was implemented.

In this example:

diff file1.txt file2.txt | code -

Note the dash as a parameter to Code.

0

Here's a couple of VBScript based solutions that may work (although .. they rely a little on apps opening on time):

pipe2key.vbs - opens the application specified as the first argument, and then sends StdIn as keystrokes to it. Needs to be used with cscript.exe as wscript does not provide StdIn access. Probably quite slow for long documents - but won't clobber the clipboard

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

Example usage: diff file1.txt file2.txt | cscript pipe2key.vbs notepad.exe

Or, pasteinto.vbs. Automates the CTRL-V operation after launching an app (thus uses the 'clip' command as mentioned in previous answers). Considerably faster and cleaner (in my opinion) than pipe2key.vbs, but the process will overwrite the clipboard

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"

Example usage: diff file1.txt file2.txt | clip && pasteinto notepad.exe

-1

Something like this "might" work.

Aw, ya didn't realize this is something you'd be doing manually each time (from the sounds of it). You might be able to make some sort of macro or something to do it for you each time to speed up the process. Not sure on that one.

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

It would have to finish writing the diff contents to file.txt in order for it to load the entirety of the diff operation which I'm not sure if it'll do. There might be a way to pause somehow between the pipe operation if that is the case.

10
  • 5
    The goal is to not create a temporary file and I'm pretty sure there's something wrong with your syntax there ;) Jun 23, 2014 at 10:00
  • "for easier review and editing later on" I figured that's what you wanted? And as Rev1.0 pointed out and amended to, it works. This is for dos however, I'm not sure if cygwin would have the same results.
    – Codezilla
    Jun 23, 2014 at 10:14
  • 3
    I guess because an & would be adequate since actually nothing needs to be "piped" between those calls.
    – Rev
    Jun 23, 2014 at 10:43
  • 3
    @Rev1.0 Correct. &, && and || are operators to chain commands together. All 3 behave differently in how they proceed if a command generates a non-0 return value. | is completely different as it is used to pipe output from one program to another. The result might be what you wanted, but using one of the chaining operators makes the intent clearer, because no actual piping is desired in that example. For additional reference: microsoft.com/resources/documentation/windows/xp/all/proddocs/… Jun 23, 2014 at 11:31
  • 1
    @Codezilla I think the idea in my post is pretty similar to yours but it's valid command prompt syntax.
    – Casey
    Jun 23, 2014 at 16:54
-3

My language is not English so sorry for mistakes.

I think u can't directly put the output into the open Notepad. May be I am wrong about it. You have to create a file with the output in it in order to work on it. The command tee can pipe the output to two or may be more commands or files in the same time.

man tee

Don't forget to use >> instead > when you redurect the output into the file. The > will overwrite the file, >> will add the output after whatever has already in that file.

1
  • 3
    tee is usually not available on Windows and even if it was, it wouldn't help with this problem. Jun 24, 2014 at 11:05
-3

You can't, Notepad is too limited for this! Better yet... install Cygwin and workaround all this "lack of features" of Windows. You can then use the command you already know.

AFAIK, very few Windows program support pipelining, even worse for GUI programs.

You can try to open feature requests to one of the "windows tail" programs to add that.

4

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .