please, is it possible to catch the output from a console program? I would like to write a GUI to console app, but I need to get its output.
If the program's output is using standard out or standard error, you can use shell redirection to redirect the program output to a file (which your GUI can read). For example:
console_app.exe >stdout.log 2>stderr.log
If you want to read the program's output in realtime (while it is running), you will need to give some more details about your GUI program. What language(s) are you using? What operating system(s)?
If you want to capture the output as the command line process runs, you want to use the Windows API function CreateProcess(). You would basically create a 'pipe' for the output and assign its handle to stdout. You'd then read from it as if it was a file while the command line program runs.
The exact implementation of how this is done will depend on what language you are using. You left that out of your question.
Related
I have a long script that runs many commands. These commands print text to the screen via standard output and standard error. I want to add some logic at the end of the script that takes all text printed to the screen (standard out or standard error) and saves it to a text file.
However, I do not want to redirect standard output and standard error to a text file because I want the user of the script to be able to see all the text getting printed to the screen in real time as the script runs. Indeed, at some points in the script, some of the commands may ask for user input. Instead, I want to be able to "GetScreenContentsText()" and then write the output of this to the screen.
Is there a way to do this in PowerShell?
As Mathias points out in a comment, the Start-Transcript cmdlet (followed by a matching Stop-Transcript call) is generally the right tool for creating session transcripts.
However, Start-Transcript doesn't capture everything and has general problems and limitations (written as of PowerShell [Core] 7.0):
Interactive prompts (Read-Host, [Console]::ReadLine()) are not transcribed - you'll see neither the prompt string nor what the user typed.
Even output can situationally be missing from the transcript, as discussed in GitHub issue #10994.
Error messages can be transcribed twice and using transcription can change the script's behavior - see GitHub issue #4645.
VT sequences (ANSI escape codes) are not captured, so any coloring shown in the console is lost.
The former of the two linked GitHub issues prompted the following response from the PowerShell committee, which reflects the status quo as of PowerShell 7.0 (emphasis added):
#PowerShell/powershell-committee reviewed this, we believe a complete solution for transcription (like the unix `script command) [is called for;] would love to see the community build a new cmdlet (published to PSGallery) that uses ptty or on Windows grabbing the screen buffer, but the ask is out of scope for the current transcription framework.
Speaking of the script utility on Unix-like platforms: while it is a superior alternative to Start-Transcript in general there (though not designed to be used from inside scripts), PowerShell's PSReadLine module, which is also used for prompting users via Read-Host, doesn't play nice with it.
As for a possible workaround: Unfortunately, it sounds like you'll have to manually duplicate prompt strings and user input in your script's output in order for them to be captured in the transcript - if modifying the script is an option.
I'm trying to redirect panic/standard error back to bash terminal with the following go code:
if err := syscall.Dup2(-1,int(os.Stderr.Fd())); err != nil {
log.Fatalf("Failed to redirect stderr to bash: %v",err)
}
But the err gives me a "bad file descriptor", probably because of the -1 I used in the first argument. I chose the value -1 because I found that int(file.(*os.File).Fd()) returned a -1 when file.Close() has been called.
As for what I'm trying to do. Elsewhere in my program, I had called a syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd())), which logs stderr to an external file. But I want stderr to point to bash terminal on occasion.
https://golang.org/pkg/syscall/ Doesn't give a verbose explanation of syscall.Dup2. I started poking around what file.Fd() returns and how it is used, but also didn't fully understand.
Can anyone tell me how to redirect stderr back to bash terminal?
You have to save the original stderr somewhere before overwriting it with your first Dup2. (In general, it’s a bad idea to use the dup2 feature of closing the target, since it can’t report errors therefrom.) Then you can Dup2 that back to int(os.Stderr.Fd()) (aka 2).
Can anyone tell me how to redirect stderr back to bash terminal?
In general, that is impossible, because a Unix program can be started (or run) without any terminal. For example, it could be started by a crontab(5) job, or thru some at or ssh command, etc. Think also of your program being run with redirections or in a pipeline, or of your program being run in a server (e.g. inside a data center); then it is likely to not have any terminal.
The common practice is for the user of your program to perhaps redirect stderr (and probably not to a terminal, but more likely to some file). Your user would use its shell for that purpose (e.g. run yourprogram 2> /tmp/errorfile; read the documentation of bash about redirections)
Terminals are quite complex stuff. You could read the TTY demystified page. See also pty(7) and termios(3). The usual way to handle terminals (on Unix) is by using the ncurses library (which has been wrapped as goncurses in Go).
Elsewhere in my program, I had called a syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd())), which logs stderr to an external file.
That is really a bad idea. Your user expects his/her stderr to stay the same (and would have redirected the stderr in his/her shell if so needed). Conventionally, you should not mess that standard streams in your program (and leave them to what they are).
A file descriptor is some small positive-or-zero index (into the file descriptor table of your process). System calls like dup2(2) are expecting valid file descriptors, and Go's syscall.Dup2 is just wrapping that dup2(2).
On Linux, you can query the file descriptor table of some process of pid 1234 by looking into the /proc/1234/fd/ directory. See proc(5) for more.
If you are absolutely certain that your program is running in a terminal, you might open /dev/tty to get it. See tty(4) for more. However, I don't recommend doing that (because you'll better design your program to be runnable outside of any terminal).
You may want to read some Linux programming book, such as ALP.
For logging purposes, Go provides its log package. See also syslog(3) and the log/syslog package of Go.
PS. I don't know Windows, but I believe it also can start programs without any terminal, e.g. as a background process. So even on Windows I would try to avoid doing that (redirection of stderr to a terminal).
I don't know why, but syscall.Dup2(0,int(os.Stderr.Fd())) returns panic stderr back to terminal.
My understanding of the linux operating system is weak. So I don't understand the significance of 0 in this context and the linux documentation.
Also, I haven't attempted this approach on a windows machine, so not sure what will happen there. I hope other people give better answers.
I want to create a generic logging application (Windows), which shall be able to execute an arbitrary executable as a child process and log the complete standard streams of a specific to a file (stdin, stdout, stderr).
Further, this logging application shall be acting like a kind of a "Man-in-the-Middle" application completely transparent, so that for user who is calling either the original executable or the wrapper logging application, there is not difference.
This functionality is somehow similar to the UNIX command line tool "tee", but as far as I found out, this tool is unfortunately not be able to log also the stdin (only stdout and stderr are supported). In addition, I want to log some more information e.g. who was the calling parent process, timestamps...
I want to use this especially for the command prompt: "cmd.exe" and rename the original and replace it with my own "cmd.exe" to automatically get a history file of all entered (stdin) commands, with its outputs (stdout, stderr).
Does someone have a good idea how to get this easily realized, perhaps with C# and pipes?
Best Regards,
Andreas
A simple version would indeed use pipes. In a native win32 app you would create some inheritable pipes and set them and the STARTF_USESTDHANDLES flag in the STARTUPINFO struct passed to CreateProcess. There is example code for this on MSDN.
You cannot however use this to replace cmd.exe because cmd.exe also uses the special Windows console API in interactive mode to implement features like the F7 history "dialog". You could take a look at some of the free terminal replacements like Console2 to see how they do it.
I have a .exe file that I've compiled on windows. But when I run it from the command line I don't see any of the things my program outputs to std::cout or std::cerr. The program runs and continues to run even after the command line returns to the prompt (it's a GUI program and doesn't quit until I press the quit button). How can I see the output of my program?
I'm using cmake to make a visual studio project which I then compile with msbuild.
One way to see the output is to run:
program.exe > output.txt
and then monitor that file for the output. Or use a pipe to view it:
program.exe | find /v ""
To also monitor the error output you could use
program.exe > output.txt 2>&1
program.exe 2>&1 | find /v ""
I figured it out based on the documentation by Microsoft that leaves a lot to the imagination and from the
much more practical examples here and here.
This helps me see "hidden" stdout and stderr messages from my (and other peoples) windows applications. It's interesting to see what messages have been left in some programs, but usually aren't seen.
The simplest approach is to rebuild the program as a console application. The option to link.exe needs to be /SUBSYSTEM:CONSOLE instead of /SUBSYSTEM:WINDOWS; presumably there is a straightforward way of specifying this in cmake.
This change shouldn't affect your GUI at all, but it will cause Windows to allocate a console if the process isn't already associated with one. Also, command line shells will usually wait for console applications to exit before continuing.
The other approach is to call AllocConsole to explicitly create a new console, or AttachConsole if you want to use an existing one. Or, of course, you could send the output to a log file.
Additional
According to a Google search, you can build the program as a console application by adding the following line to your source code:
#pragma comment(linker, "/SUBSYSTEM:CONSOLE")
This is probably the easiest solution. You can put it in an #if block if you only want the console for debug builds.
See also CMake: How to use different ADD_EXECUTABLE for debug build?
Harry Johnston's answer is spot-on if you want to permanently alter your application to display this information. I would recommend the latter approach he suggests, because switching your app to targeting the console subsystem will cause it to always allocate and display a console window on startup, even if you don't want it to.
However, I notice that you mention you want to display output from std::cerr, which implies that you might be only interested in this information for debugging purposes. In that case, my recommendation would be to call the OutputDebugString function instead of outputting to either std::cout or std::cerr. Then, you can use a little utility like DebugView to monitor the debug output of your application. Everything it sends to the OutputDebugString function will be displayed in the DebugView window.
If you want to use this setup with minimal changes to your existing code base, you can actually redirect the output of streams like std::cout and std::cerr to the debugger, just as if you'd called the OutputDebugString function. Advice on how to do this can be found in the answers to this question and in this blog post.
Windows doesn't support dual mode. Which means that when you run gui, you cannot get output to your console that you run the app from.
Background: We develop win32 applications, and use the "Thompson Toolkit" on windows to give us a unix-like shell that we use as our command-line.
We have a GUI program (with a WinMain and message loop) that we want to write to the console, but printf and so on don't work, even when we launch the program from the console. How can we write to the console from a GUI program? We need to print text there so that an automated build system can display error messages and so on.
Thanks.
In short, you need to attach a console. For details and ready to use code, see http://www.codeproject.com/KB/dialog/ConsoleAdapter.aspx.
Basicly you have to create a console by your self with AllocConsole, AttachConsole. After that you have to get standard handles with GetStdHandle and "associates a C run-time file descriptor with an existing operating-system file handle" with help of _open_osfhandle.
The returned handle can be used to overwrite crt stdin and stdout. After that all crt methods like printf should work.
Instead of logging to the console, log to a file and then track the file with a separate gui application. This keeps the console uncluttered and gives you a more persistent record of your log, which occasionally is extremely useful. There are various libraries which will do most of this for you, or you can keep it simple and just do it yourself.
somewhere in the Visual Studio Project Settings you can switch on having a console, assuming you are using VS. (Can't say where because I currently don't have it)