Skip to content

Instantly share code, notes, and snippets.

@gythialy
Last active March 27, 2023 14:13
Show Gist options
  • Select an option

  • Save gythialy/2800bcbec09df4664b3c to your computer and use it in GitHub Desktop.

Select an option

Save gythialy/2800bcbec09df4664b3c to your computer and use it in GitHub Desktop.
Windows equivalent to Linux ‘watch’ command
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;
}
}
}
@ECHO OFF
:loop
cls
%*
timeout /t 5
goto loop
@gythialy

Copy link
Copy Markdown
Author

Usage

D:\t>watch dir *.db

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment