Last active
March 27, 2023 14:13
-
-
Save gythialy/2800bcbec09df4664b3c to your computer and use it in GitHub Desktop.
Windows equivalent to Linux ‘watch’ command
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Threading.Tasks; | |
| using System.Diagnostics; | |
| namespace watch | |
| { | |
| class Program | |
| { | |
| public struct processReturn | |
| { | |
| public int exitCode; | |
| public string[] exitText; | |
| public string exitErr; | |
| } | |
| static void Main(string[] args) | |
| { | |
| double pauseSeconds = 2; | |
| //bool diffEnabled = false; | |
| string commandString = ""; | |
| bool commandFound = false; | |
| double maxExecutions = 0; | |
| double currentExecutions = 0; | |
| int tmpWidth = Console.WindowWidth; | |
| int tmpHeight = Console.WindowHeight; | |
| Console.WindowWidth = Console.LargestWindowWidth; | |
| Console.WindowHeight = Console.LargestWindowHeight; | |
| Console.WriteLine("watch Copyright (c) Garrett Galloway 2014."); | |
| Console.Title = "watch for Windows by Garrett Galloway 2014"; | |
| Console.WindowWidth = tmpWidth; | |
| Console.WindowHeight = tmpHeight; | |
| if (args.Count() < 1) | |
| { | |
| printHelp(); | |
| } | |
| else | |
| { | |
| int argCount = args.Count(); | |
| int currentArg = 0; | |
| while (currentArg < argCount) | |
| { | |
| if (args[currentArg] == "/n") | |
| { | |
| if (args.Count() < 2) | |
| { | |
| Console.WriteLine("Missing <seconds> argument."); | |
| printHelp(); | |
| break; | |
| } | |
| currentArg++; | |
| try | |
| { | |
| pauseSeconds = double.Parse(args[currentArg]); | |
| if (!(pauseSeconds > 0)) | |
| { | |
| pauseSeconds = 1; | |
| } | |
| } | |
| catch | |
| { | |
| Console.WriteLine("\"" + args[currentArg] + "\" does not appear to be a valid number"); | |
| printHelp(); | |
| } | |
| } | |
| else if (args[currentArg] == "/m") | |
| { | |
| if (args.Count() < 2) | |
| { | |
| Console.WriteLine("Missing <executions> argument."); | |
| printHelp(); | |
| break; | |
| } | |
| currentArg++; | |
| try | |
| { | |
| maxExecutions = double.Parse(args[currentArg]); | |
| if (maxExecutions < 1) | |
| { | |
| maxExecutions = 1; | |
| } | |
| } | |
| catch | |
| { | |
| Console.WriteLine("\"" + args[currentArg] + "\" does not appear to be a valid number"); | |
| printHelp(); | |
| } | |
| } | |
| else if (args[currentArg] == "/d") | |
| { | |
| //diffEnabled = true; | |
| Console.WriteLine("Differential comparison not yet implemented."); | |
| break; | |
| } | |
| else if (args[currentArg] == "/?") | |
| { | |
| printHelp(); | |
| }else | |
| { | |
| commandString = args[currentArg++]; | |
| while(currentArg < args.Count()) | |
| { | |
| commandString = commandString + " " + args[currentArg++]; | |
| } | |
| Console.Title = "watch - '" + commandString + "'"; | |
| commandFound = true; | |
| } | |
| currentArg++; | |
| } | |
| } | |
| //esure there is a command to execute | |
| if (commandFound) | |
| { | |
| bool notDone = true; | |
| System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); | |
| //whole console output variable | |
| StringBuilder outConsole = new StringBuilder(); | |
| //builds first top status | |
| string progExec = "Every " + pauseSeconds.ToString("N1") + "s: " + commandString; | |
| string progDT = System.DateTime.Now.ToString(); | |
| int padSpaces = (Console.WindowWidth - progDT.Length) > 10 ? (Console.WindowWidth - progDT.Length) : 10; | |
| //outputs directly to console just in case the command takes a while to execute | |
| Console.WriteLine(progExec.PadRight(padSpaces, ' ') + progDT + Environment.NewLine); | |
| //main loop | |
| while ((notDone == true && maxExecutions == 0) || (notDone == true && maxExecutions > currentExecutions)) | |
| { | |
| sw.Reset(); | |
| //builds top status and adds to console out buffer | |
| progExec = "Every " + pauseSeconds.ToString("N1") + "s: " + commandString; | |
| progDT = System.DateTime.Now.ToString(); | |
| padSpaces = (Console.WindowWidth - progDT.Length) > 10 ? (Console.WindowWidth - progDT.Length) : 10; | |
| outConsole.AppendLine( progExec.PadRight(padSpaces, ' ') + progDT + Environment.NewLine); | |
| sw.Start(); | |
| //executes process and captures return information | |
| processReturn commandReturns = executeProcess(commandString); | |
| currentExecutions++; | |
| //calculates how many lines of output to display on screen | |
| //ignores overflow to prevent console text instability/flickering | |
| for (int i = (Console.WindowHeight - 6) > commandReturns.exitText.Length ? commandReturns.exitText.Length - 1 : (Console.WindowHeight - 6); i > 0; i--) | |
| { | |
| outConsole.AppendLine(commandReturns.exitText[commandReturns.exitText.Length - i]); | |
| } | |
| //adds error information if any was attained | |
| //messes up console text scrolling overflow prevention | |
| if (commandReturns.exitErr != "") | |
| { | |
| outConsole.AppendLine(Environment.NewLine + "StandardErr:" + Environment.NewLine + commandReturns.exitErr); | |
| } | |
| //bottom status and instructs | |
| outConsole.AppendLine(Environment.NewLine + "Current executions: " + currentExecutions.ToString() + ((maxExecutions > 0) ? " (Max: " + maxExecutions + ")" : "") + "."); | |
| outConsole.Append("Press 'n' to skip waiting. Press 'c' or 'ctrl+c' to cancel."); | |
| //clear console, write console, and start a new output buffer | |
| Console.Clear(); | |
| Console.Write(outConsole.ToString()); | |
| outConsole = new StringBuilder(); | |
| //loop to handle the actual timeout before next execution | |
| while (sw.ElapsedMilliseconds < pauseSeconds * 1000) | |
| { | |
| //checks for relevant keypress events | |
| if (Console.KeyAvailable) | |
| { | |
| ConsoleKeyInfo keypress = Console.ReadKey(); | |
| if (keypress.Key == ConsoleKey.C) | |
| { | |
| notDone = false; | |
| break; | |
| }else if (keypress.Key == ConsoleKey.N) | |
| { | |
| break; | |
| } | |
| } | |
| //system threading friendly sleeping so that we arent killing cpu | |
| System.Threading.Thread.Sleep(1); | |
| } | |
| } | |
| } | |
| //debugging routine | |
| if (System.Diagnostics.Debugger.IsAttached) | |
| { | |
| // //print debug variables | |
| // Console.WriteLine("Command string: '" + commandString + "'."); | |
| // Console.WriteLine("Differential enabled: " + ((diffEnabled == true) ? "true." : "false.")); | |
| // Console.WriteLine("Pause seconds: " + pauseSeconds.ToString() + "."); | |
| // Console.WriteLine("Max executions: " + ((maxExecutions > 0) ? maxExecutions.ToString() + "." : "No Max.")); | |
| // Console.Write("Args (csv): "); | |
| // if (args.Count() > 0) | |
| // { | |
| // Console.Write(args[0]); | |
| // int i; | |
| // for (i = 1; i < args.Count(); i++) | |
| // { | |
| // Console.Write(", " + args[i]); | |
| // } | |
| // Console.WriteLine("<EOL>."); | |
| // } | |
| // else | |
| // { | |
| // Console.WriteLine("<EOL>."); | |
| // } | |
| // //hold console open | |
| Console.WriteLine(Environment.NewLine + "PRESS ANY KEY TO CONTINUE."); | |
| Console.ReadKey(false); | |
| } | |
| } | |
| //function to print help menu | |
| static void printHelp() | |
| { | |
| Console.WriteLine("Usage:"); | |
| Console.WriteLine("watch [/n <seconds>] [/m <executions>] [/h] <command + args>"); | |
| Console.WriteLine("/n <seconds> Wait time in seconds between <command + args>. Default: 2."); | |
| Console.WriteLine("/m <executions> Max number of executions. Default: Unlimited."); | |
| //Console.WriteLine("/d Enable difference highlighting between command executions."); | |
| Console.WriteLine("/? Display this help text."); | |
| Console.WriteLine(Environment.NewLine + "Example: watch /n 4 \"dir c:\\windows\"" + Environment.NewLine + Environment.NewLine); | |
| } | |
| //function that creates a process runs it and returns relevant data | |
| static processReturn executeProcess(string commandInputString) | |
| { | |
| processReturn pr = new processReturn(); | |
| ProcessStartInfo processInfo; | |
| Process process; | |
| processInfo = new ProcessStartInfo("cmd.exe", "/C " + commandInputString); | |
| processInfo.CreateNoWindow = true; | |
| processInfo.UseShellExecute = false; | |
| processInfo.RedirectStandardOutput = true; | |
| processInfo.RedirectStandardError = true; | |
| process = Process.Start(processInfo); | |
| process.WaitForExit(); | |
| pr.exitCode = process.ExitCode; | |
| pr.exitText = process.StandardOutput.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.None); | |
| pr.exitErr = process.StandardError.ReadToEnd(); | |
| process.Close(); | |
| return pr; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @ECHO OFF | |
| :loop | |
| cls | |
| %* | |
| timeout /t 5 | |
| goto loop |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage