#!/usr/bin/env python '''Rearrange a series of lines on stdin into a random order''' import os import sys import random import python2x3 def usage(retval): '''Give a usage message''' sys.stderr.write('Usage: %s [-0] [-h|--help]\n' % sys.argv[0]) sys.stderr.write('-0 gives null termination instead of newline termination\n' % sys.argv[0]) sys.exit(retval) def newlines(): '''Generate lines of text, minus their newline terminator''' for line in sys.stdin: if line[-1:] == '\n': yield line[:-1] else: yield line def my_range(maximum): '''Generate the values from 0..maximum-1, for consistent semantics between python 2.x and python 3.x''' value = 0 while value < maximum: yield value value += 1 def shuffle(list_, num_elements, verbose, every_n): '''rearrange elements of list_ into random order''' randobj = random.Random() for element_no in my_range(num_elements): if verbose and element_no % every_n == 0 and element_no != 0: sys.stderr.write('%f%% done\n' % (float(element_no) * 100.0 / float(num_elements))) random_element_no = int(randobj.random() * num_elements) list_[element_no], list_[random_element_no] = list_[random_element_no], list_[element_no] def get_input(generator, verbose, every_n): '''Get the lines of input we need to rearrange''' list_ = [] for element_no, line in enumerate(generator()): if verbose and element_no % every_n == 0 and element_no != 0: sys.stderr.write('read %d lines\n' % element_no) list_.append(line) num_elements = len(list_) return list_, num_elements def main(): '''Main function''' use_readline0 = False verbose = False every_n = 1000 while sys.argv[1:]: if sys.argv[1] == '-0': use_readline0 = True elif sys.argv[1] == '-v': verbose = True elif sys.argv[1] in [ '-h', '--help' ]: usage(0) else: sys.stderr.write('%s: Illegal option: %s\n' % (sys.argv[0], sys.argv[1])) usage(1) del sys.argv[1] if use_readline0: import readline0 if use_readline0: generator = readline0.readline0 terminator = python2x3.string_to_binary('\0') else: #generator = sys.stdin.readline generator = newlines terminator = python2x3.string_to_binary('\n') list_, num_elements = get_input(generator, verbose, every_n) if verbose: sys.stderr.write('Read a total of %d lines, about to start swaps\n' % num_elements) shuffle(list_, num_elements, verbose, every_n) if verbose: sys.stderr.write('Done with swaps\n') for element in list_: os.write(1, python2x3.string_to_binary(element) + terminator) main()