#! /usr/bin/awk -f # mc: Multi-column printer. Parameterized version. # Prints each line of input file(s) in output columns. Input files are assumed # to contain a single word on each line, and that word to be relatively short. # 5 columns in a 60-character line, if maximum column with is 10 characters. # Options can appear anywhere on the command line, same option can appear # multiple times, the later one takes precedence. Options are of the form # : followed by a letter, as in :e; or : followed by 2 to 3 digits number, # followed by : followed by 1 to 2 digits number. It is :screen:maximum, where # screen is the length of an output string in characters, maximum is the length # of each field in output line. To set different output mode for different # input files, precede them with an option :option on the command line. # Usage: # 1st 3 forms reads standard input, press Control-D to exit: # ./mcP.awk # ./mcP.awk :e # ./mcP.awk :87:7 :i # ./mcP.awk llines.txt # ./mcP.awk :e llines.txt # ./mcP.awk :30:5 :i llines.txt # ./mcP.awk :46:8 :i llines.txt :e llines.txt :t llines.txt # ./mcP.awk llines.txt :e llines.txt llines.txt :i llines.txt :50:12 # Calling program with different interpreter (default is gawk): # gawk -f ./mcP.awk llines.txt # mawk -f ./mcP.awk llines.txt # busybox awk -f ./mcP.awk llines.txt BEGIN { # Default widths in characters: # screen: from 10 upto 146, screen = 60 # maximum: from 5 upto 99. maximum = 10 # Allowed options for dealing with long lines in the output: # insert ellipses in the middle, opts[":e"] = 1 # truncate long lines with indicator, opts[":i"] = 1 # truncate long lines without indicator. opts[":t"] = 1 # Default mode is :t. mode = ":t" for (i = 1; i < ARGC; i++) if(ARGV[i] ~ /^:[[:alpha:]]$/) { nOpts++ if (ARGV[i] in opts) mode = ARGV[i] # Setting ARGV[i] to "" to stop awk from treating it as filename. ARGV[i] = "" # mawk does not understand [0-9]{2,3}; gawk and busybox awk understand. } else if (ARGV[i] ~ /^:[0-9][0-9][0-9]?:[0-9][0-9]?$/) { nOpts++ # Argument is in form of :screen:maximum. split(ARGV[i], width, ":") if (width[3] < 5) maximum = 5 else maximum = width[3] if (width[2] > 146) screen = 146 else screen = width[2] if (screen <= maximum) screen = maximum # Setting ARGV[i] to "" to stop awk from treating it as filename. ARGV[i] = "" } else file[++fn] = mode # If there are no filenames on the command line, add stdin to ARGV. if (++nOpts == ARGC) { ARGV[ARGC++] = "-" file[++fn] = mode } # In case user pressed Control-D as 1st action at stdin: record["1"] = 1 } # BEGIN # When reading 1st line of the next input, add NR to record array. FNR == 1 { record[NR] = ++rn } # Store all lines in an array, determine maximum output column width. { lines[NR] = $0 if (length($0) > max) max = length($0) } END { # Limit the width of output columns. if (max > maximum) max = maximum # Assemble format string for output columns. fmt = sprintf("%%-%d.%ds", max, max) # Compute the number of columns. ncol = int(screen / (max + 2)) if (ncol < 1) ncol = 1 # Produce the output. Output mode can change between input files. for (i = 1; i <= NR; i += ncol) { out = "" for (j = i; j < i + ncol && j <= NR; j++) { if (j in record) mode = file[record[j]] fixLine(lines[j], mode) } # Remove extra spaces at the end of each output string. sub(/ +$/, "", out) print out } } # END # The function fixLine will change the output of long lines according to mode. # :t - truncate long lines without indicator (happens automatically by fmt). function fixLine(line, mode, m) { if (length(line) > maximum) { if (mode == ":e") { # :e - insert ellipses in the middle. m = maximum / 2 line = substr(line, 1, m - 1) "..." substr(line, length(line) - m + 3) } else if (mode == ":i") { # :i - truncate long lines with indicator. m = maximum - 3 line = substr(line, 1, m) "..." } } out = out sprintf(fmt, line) " " } # function fixLine