Simple Unix Like commands using C#

This article presents some small toy console applications that emulate the Unix command like behavior on Windows.

Background

A while ago, my cousin (age: 10 years approx) came to me and asked me to install Unix on his computer. I asked him why he needed that, as a 10 year boy has little to do with Unix. He then told me that he needed to practice an assignment that involves running some Unix commands. He showed me a list of commands that he needed to run.

  • ls
  • cd
  • pwd
  • mkdir
  • rmdir
  • cp
  • mv
  • rm
  • cat
  • more
  • grep
  • whoami
  • ps

I was not ready to put Linux on his machine just to run these basic commands. I could give him something like “cygwin” or “coreutils” and he would be fine. Then I thought, Windows already has these commands but with some other names so why not just create a wrapper around those and/or write simple 2-3 line programs to emulate these commands. So I spent half an hour in front of the computer and created these basic commands. Although they are not a very good replacement for the real Unix environment, I guess it was good enough for that 10 year old boy’s assignment. So here I am sharing these small utilities.

Using the Code

After I was done with this small exercise, the status of commands was:

ls     - Implemented simple optionless
cd     - Not Implemented as it exist in windows too
pwd    - Implemented
mkdir  - Not Implemented as it exist in windows too
rmdir  - Not Implemented as it exist in windows too
cp     - Implemented
mv     - Implemented
rm     - Implemented
cat    - Implemented
more   - Implemented (windows has its own version but ours will work along with that)
grep   - Implemented
whoami - Implemented
ps     - Implemented (optionless)

So let us look at the small code snippets written for these tiny programs.

ls

static void Main(string[] args)
{
    if (args.Length == 0)
    {
        DirectoryInfo dir = new DirectoryInfo(Directory.GetCurrentDirectory());

        foreach (DirectoryInfo d in dir.GetDirectories())
        {
            Console.WriteLine("{0, -30}\t directory", d.Name);
        }

        foreach (FileInfo f in dir.GetFiles())
        {
            Console.WriteLine("{0, -30}\t File", f.Name);
        }
    }           
}

pwd

static void Main(string[] args)
{
    Console.WriteLine(Directory.GetCurrentDirectory());
}

cp

static void Main(string[] args)
{
    if (args.Length != 2)
    {
        Console.WriteLine("The syntax of the command is incorrect.");
    }
    else
    {
        if (File.Exists(args[0]) == false)
        {
            Console.WriteLine("Source file not found");
        }
        else if (Directory.Exists(args[1]) == false)
        {
            Console.WriteLine("Target Directory not found");
        }
        else
        {
            File.Copy(args[0], args[1] + "\\" + args[0]);
        }
    }
}

mv

static void Main(string[] args)
{
    if (args.Length != 2)
    {
        Console.WriteLine("The syntax of the command is incorrect.");
    }
    else
    {
        if (File.Exists(args[0]) == false)
        {
            Console.WriteLine("Source file not found");
        }
        else if (Directory.Exists(args[1]) == false)
        {
            Console.WriteLine("Target Directory not found");
        }
        else
        {
            File.Move(args[0], args[1] + "\\" + args[0]);
        }
    }
}

rm

static void Main(string[] args)
{
    if (args.Length != 1)
    {
        Console.WriteLine("The syntax of the command is incorrect.");
    }
    else
    {
        if (File.Exists(args[0]) == false)
        {
            Console.WriteLine("File not found");
        }
        else
        {
            Console.WriteLine("Are you sure you want to delete {0} (y/n)", args[0]);
            ConsoleKeyInfo key = Console.ReadKey();
            if (key.Key == ConsoleKey.Y)
            {
                File.Delete(args[0]);
                Console.WriteLine("\nFile Deleted: {0}", args[0]);
            }
        }
    }
}

cat

static void Main(string[] args)
{
    if (args.Length != 1)
    {
        Console.WriteLine("The syntax of the command is incorrect.");
    }
    else
    {
        if (File.Exists(args[0]) == false)
        {
            Console.WriteLine("File not found");
        }
        else
        {
            string contents = File.ReadAllText(args[0]);
            Console.Write(contents);
        }
    }
}

more

class Program
{
    static void Main(string[] args)
    {
        Process.Start("cat " + args[0] + " | more");
    }
}

grep

static void Main(string[] args)
{
    if (args.Length != 2)
    {
        Console.WriteLine("The syntax of the command is incorrect.");
    }
    else
    {
        if (File.Exists(args[1]) == false)
        {
            Console.WriteLine("File not found");
        }
        else
        {
            string[] lines = File.ReadAllLines(args[1]);

            foreach (string line in lines)
            {                        
                if(line.Contains(args[0]))
                {
                    Console.WriteLine(line);
                }
            }
        }
    }
}

whoami

static void Main(string[] args)
{
    Console.WriteLine(Environment.UserName);
}

ps

static void Main(string[] args)
{
    Process[] mYProcs = Process.GetProcesses();

    Console.WriteLine("-----------------------------------------------------");
    Console.WriteLine("{0, -8} {1, -30} {2, -10}", "PID", "Process Name", "Status");
    Console.WriteLine("-----------------------------------------------------");

    foreach (Process p in mYProcs)
    {
        try
        {
            Console.WriteLine("{0, -8} {1, -30} {2, -10}", p.Id, 
            p.ProcessName, p.Responding ? "Running" : "IDLE");
        }
        catch (Exception)
        {
            continue;
        }
    }
}

NOTE: Check out the source code for implementation.

IMPORTANT: The folder that contains these commands should be added in the PATH environment variable.

Points of Interest

At the end of this exercise, I thought about what I did and the only thing I could think of is that perhaps I should have used C++ to implement these commands. That way, I could relieve the users from the burden of having the .NET runtime on their system. But since it solved my purpose, I didn’t spend much time on it later. Perhaps, when I get time, I would like to do some more things like:

  • Having all the Unix commands implemented and not just these few
  • Write similar programs in C++
  • Perhaps write the wrappers for Unix like system calls to work on Windows

I will get to these activities once I get some free time from my “real” job.

Download sample code for this article: unixlike_src