Wednesday, January 25, 2012

UNIX Utilities IV: cat

This is probably one of the most useful commands on any UNIX system, it almost becomes a third arm for most users, essential for navigating a world where everything is a file.

/**
* A copy of the "cat" command on UNIX, missing a few options, but it
* does what is normally asked of it (reading files).
*
* About 1/4 the size of the GNU one without stripping.
*
* Copyright 2012-01-25 Joseph Lewis
*/
#include <iostream>
#include <fstream>
#include <string.h>
#include <stdio.h>
using namespace std;

int main(int nargs, char* vargs[])
{
// General help behaviour.
if(strcmp(vargs[0],"--help") == 0 || strcmp(vargs[0], "-h") == 0)
{
cout << "Usage: " << vargs[0] << " filename [filename ...]" << endl;
cout << "\tPrints the contents of the given file(s)" << endl;
return 1;
}

// If the only arg is the program name, read from stdin.
if(nargs == 1)
{
while(cin.good())
{
string line;
getline(cin,line);
cout << line << endl;
}

return 0;
}

// If the program has args, try to read the files.
for(int i = 1; i < nargs; i++)
{
string line;
ifstream myfile;
myfile.open (vargs[i]);

if(myfile.bad() || myfile.fail())
{
cout << "cat: "<< vargs[i] << ": No such file or directory" << endl;
}

while ( myfile.good() )
{
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}
return 0;
}

Tuesday, January 17, 2012

Get the PID of a started process in BASH

Sometimes (like when writing init scripts) it is necessary to get the PID of a child process that you started, this one-liner does that by listing processes grepping for the one you created (in this case "ls"), and cutting the PID from the last one in that list:

LPID=$(ps -A | grep ls | grep -v grep | tail -n1 | cut -d\  -f2)

Sunday, January 15, 2012

INITV Style Startup Script in Python

Projects like Upstart and systemd are incredibly nice with the ease that they provide for creating system startup processes, but nothing can beat initv for portability and widespread use/knowledge.

The major problem with most init style scripts is they run lots of processes and can be a mess to get working the first time: here is a plug n' play solution, just replace the ARGS with the program you want to run and the program's arguments. In the provided example, it opens chromium (the open source version of Google Chrome) in kiosk mode to this site (press Alt + F4 to exit).

#!/usr/bin/env python
'''
2012-01-15 Joseph Lewis <joehms22@gmail.com>

Provides init-like handling of a program.
'''

import os
import sys
import signal
from subprocess import Popen


ARGS = ["chromium-browser", "--kiosk", "http://onehourhacks.blogspot.com"]
PIDFILE = "/tmp/%s.pid" % (ARGS[0])


try:
cmd = sys.argv[1]
except IndexError, e:
print("Usage: %s (start|stop|restart)" % (sys.argv[0]))
exit(2)


def start():
try:
j = open(PIDFILE)
j.close()
print("Already running!")
return
except IOError:
pid = Popen(ARGS).pid
j = open(PIDFILE, 'w')
j.write(str(pid))
j.close()


def stop():
try:
j = open(PIDFILE)
os.kill(int(j.read()),signal.SIGTERM)
j.close()
os.remove(PIDFILE)
except IOError, e:
print("Cannot stop: the program is not running")
except OSError, e:
os.remove(PIDFILE)
print("The program has quit before it was killed")


# Very simple stuff here, initv style!
if cmd.lower() == "start":
start()

if cmd.lower() == "stop":
stop()

if cmd.lower() == "restart":
print("Restarting")
stop()
start()

Monday, January 9, 2012

UNIX Utilities III: Yes

This isn't a hugely popular program, but it does have its uses: the basic "yes" command, simply repeats whatever you put in to it, over and over and over again. This can be handy for things like testing buffering on a new shell you're developing.

Note that the usage is incredibly similar to echo, but simply provides it in a for loop:

/**
* A utility that emulates the UNIX command "yes", repeating the input
* until killed.
*
* Used in places like Jurassic Park (the movie) when Nedry leaves a
* trap that outputs the string "You didn't say the magic word!" over
* and over.
*
* Copyright 2011-12-23 Joseph Lewis <joehms22@gmail.com>
*/

#include <iostream>

using namespace std;

int main(int nargs, char* vargs[])
{
string s;

for(int i = 0; i < nargs - 1; i++)
{
if(i != 0)
s += " ";
s += vargs[i + 1];
}
s += "\n";

while(true)
{
cout << s;
}
}

Saturday, January 7, 2012

UNIX Utilities II: True and False

It is occasionally useful to check the outputs of commands in bash scripts; it is even more useful to test your scripts for all eventualities before you release them, to make sure strange errors don't begin occurring once they have been run in a variety of environments; this is where "true" and "false" come in.

These two simple programs simply return 0, or 1 as an exit status when run. This is probably the only case in a UNIX system where you will see 1 denoting a success.

Once compiled, these programs end up being about 8.3 kb on my system, which is almost a third the size of the GNU versions, how this happened, I have no idea; they are in essence the simplest programs in the world:

/**
* true - Probably the simplest program in the world, does nothing, and
* succeeds at it. Not very realistic, I know, but this is UNIX after
* all, not the real world where not doing anything makes you a failure.
*
* Copyright 2011-12-23 Joseph Lewis <joehms22@gmail.com>
*/

int main()
{
return 0;
}

/**
* false
* Probably the (second) simplest program in the world, does nothing,
* and fails at it. Note that this is the second because "true" is the
* first.
*
* Copyright 2011-12-23 Joseph Lewis <joehms22@gmail.com>
*/

int main()
{
return 1; // FAIL
}