Piperate

Piperate is a handy tool written by Michael Lyle to limit the bandwidth of a unix pipe. Adapted to use nanosleep() instead of sleep() by Tim Starling.
Download: http://wikimedia.org/~tstarling/piperate.c
Or just copy and paste:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include 
#include <errno.h>
#include <unistd.h>
/* piperate - v0.3, by Michael Lyle <mlyle@lyle.org> and Tim Starling.
** Last updated February 2006.
** This software is in the public domain.
**
** usage: piperate [-b blocksize] [-d delay] [-a] [-p]
**
** reads from stdin and writes to stdout; aggregates writes to
** size blocksize; ensures at least delay seconds between writes.
** Delay may be a floating point number, e.g. 2e-3 for 2ms.
**
** if -a is set, it always sleeps delay seconds before a write,
** even if more than delay seconds elapsed since the prev write
**
** if -p is set, it will print out a '.' after each block read to
** standard error for progress notification.
**
** To build: gcc -o piperate piperate.c
*/
int readFullBuf(int fd, char *buf, size_t nBytes) {
 int numRead=0;
 while (numRead < nBytes) {
 int curRead;
 curRead=read(fd, buf+numRead, nBytes-numRead);
 if (curRead == -1) {
 switch (errno) {
	case EINTR:
	case EAGAIN:
	 break;
 }
 perror("read");
 return numRead;
 }
 if (curRead == 0) {
 /* eof */
 return numRead;
 }
 numRead += curRead;
 }
 return numRead;	/* success */
}
/* Based on the function given in the glibc manual */
int timespec_subtract (struct timespec *result, struct timespec *x, 
 struct timespec *y)
{
 /* Perform the carry for the later subtraction by updating y. */
 if (x->tv_nsec < y->tv_nsec) {
 int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
 y->tv_nsec -= 1000000000 * nsec;
 y->tv_sec += nsec;
 }
 if (x->tv_nsec - y->tv_nsec > 1000000000) {
 int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
 y->tv_nsec += 1000000000 * nsec;
 y->tv_sec -= nsec;
 }
 /* Compute the time remaining to wait.
 tv_nsec is certainly positive. */
 result->tv_sec = x->tv_sec - y->tv_sec;
 result->tv_nsec = x->tv_nsec - y->tv_nsec;
 /* Return 1 if result is negative. */
 return x->tv_sec < y->tv_sec;
}
int main(int argc, char *argv[]) {
 int bufSize=1048576;
 double delay=5;
 int alwaysSleepFull=0;
 struct timespec lastWriteTime, toSleep, tsDelay, currentTime, remaining;
 int progress=0;
 char *buf;
 int ch;
 gettimeofday(&lastWriteTime, NULL);
 while ((ch = getopt(argc, argv, "b:d:ap")) != -1) {
 switch(ch) {
 case 'a':
 alwaysSleepFull=1;
	break;
 case 'b':
 bufSize=atoi(optarg);
	break;
 case 'd':
	delay=atof(optarg);
	break;
 case 'p':
	progress=1;
	break;
 default:
	fprintf(stderr, "usage: %s [-b blocksize] [-d delay] [-a] [-p]\n", 
		argv[0]);
	exit(1);
 }
 }
 tsDelay.tv_sec = (int)delay;
 tsDelay.tv_nsec = (int)((delay - (int)delay) * 1e9); 
 buf=malloc(bufSize);
 if (!buf) {
 perror("malloc");
 return 1;			/* unable to allocate the buffer */
 }
 while (1) {
 int numRead;
 numRead=readFullBuf(0, buf, bufSize);
 if (progress) {
 fprintf(stderr, ".");
 }
 if (alwaysSleepFull) {
 nanosleep(&tsDelay, &remaining);
 } else {
 gettimeofday(¤tTime, NULL);
 timespec_subtract(&toSleep, ¤tTime, &lastWriteTime);
 timespec_subtract(&toSleep, &tsDelay, &toSleep);
 /* fprintf(stderr, "delaying %d.%09d seconds...\n", toSleep.tv_sec, toSleep.tv_nsec); */
 if (toSleep.tv_sec > 0 || (toSleep.tv_sec == 0 && toSleep.tv_nsec > 0)) {
	nanosleep(&toSleep, NULL);
 }
 }
 gettimeofday(&lastWriteTime, NULL);
 write(1, buf, numRead);
 if (numRead < bufSize)
 break;			/* we're done here */
 }
}