diff/cmp for remote files
December 24, 2009
rdiff, rcmp – diff remote files
rdiff and rcmp extends the diff and cmp utilities to remote files.
Each file or directory argument is either a remote filename of the form [[user@]host1:]file, or a local filename.
Note: the scp program is used to retrieve a remote file. Setting up ssh authentication (~/.ssh/authorized_keys on the remote host ) may be required. Google ‘ssh authorized keys’ for info.
Note2: rdiff can be hardlink’d to rcmp (ie: ln rdiff rcmp). The filename is used to determine functionality.
Example usages:
$ rdiff -b produser@prodhost:/home/prod/bin/xyz.sh xyz.sh
$ rcmp produser@prodhost:/home/prod/javalib/xyz.jar $HOME/dev/java/lib/xyz.jar
$ rcmp ruser@rhost:/usr/local/abc:def /usr/local/abc:def
#! /bin/sh
# Name:
# Synopsis: rdiff [-b] [[user@]host1:]file1 [[user@]host2:]file2
# rcmp [[user@]host1:]file1 [[user@]host2:]file2
# Description: Run diff/cmp on remote files.
# Note: This script uses scp or rcp to copy remote files.
# (~/.ssh/.authorized_keys, or ~/.rhosts may need to be configured)
# Note2: Simple pattern matching is used to determine if a file is remote or local
# The filename matches a "user@host:" or "host:" prefix pattern. To force
# a match for a local file, specify the full path with the leading '/'.
getfile()
{
if perl -e 'exit !(($ARGV[0] =~ /.*\@.*:\/.*/) || ($ARGV[0] =~ /.*:\/.*/)) &&
!($ARGV[0] =~ /\/.*/);' $1; then
scp "$1" "$2"
# rcp "$1" "$2"
else
ln "$1" "$2"; # This is slight overkill, after all we already
# have the file. But, it simplifies file cleanup...
fi
}
# Main
case $0 in
*rdiff) cmd=diff;;
*rcmp) cmd=cmp;;
esac
while getopts b opt; do
case $opt in
b) options="${options} -b";;
esac
done
shift `expr $OPTIND - 1`
TMPDIR=$HOME/.tmp
tmpfile1=$TMPDIR/r${cmd}1.$$
tmpfile2=$TMPDIR/r${cmd}2.$$
trap "rm -f $tmpfile1 $tmpfile2" 0 15
if getfile "$1" "$tmpfile1" && getfile "$2" "$tmpfile2"; then
eval $cmd $options $tmpfile1 $tmpfile2
fi
clone.c
December 12, 2009
Here’s a fun, short program.
The primary goal is to write a program that outputs the source code of the program when it is executed (ie: clone itself). A secondary goal is to make the program as small as possible.
Here’s a sh/ksh/csh/bash implementation:
cat $0
Here’s a version written in C:
char *s="char *s=%c%s%c; main() { printf(s,34,s,34); putchar(0x0a); }"; main() { printf(s,34,s,34); putchar(0x0a); }
getopts.java – command line parser for Java
November 25, 2009
getopts.java is a simple parser for java. It is based on the Unix getopts shell utility of the same name.
Example usage: See main() below.
/* Name: $Id$
* Description: getopts is a simple command line parser based on the getopts shell parser.
*/
package HHjlib;
public class getopts
{
private String argv[];
private int argc;
private int optind = 0;
private int optind2 = 0;
private String optarg;
/** Initialize the getopts parser with the command line argument array */
public getopts(String args[])
{
argv = args;
argc = args.length;
optind = 0;
optind2 = 1;
}
/** The getOption() method parses positional parameters.
The optstring parameter contains the option characters to be recognized;
If a character is followed by a colon, the option is required to have an argument.
Note: The colon and question mark characters may not be used as option characters.
Each time it is invoked, getOption() returns the next option. If an option requires
an argument, the argument may be retrieved using the getOptionArg() method after
getOption() processing. If an invalid option is seen, getOption() returns a '?'.
When the end of options is encountered, getopts returns the null character.
*/
public char getOption(String optstring)
{
if (optind >= argc || argv[optind].charAt(0) != '-')
return '';
char argv_option = argv[optind].charAt(optind2);
int optlen = optstring.length();
for (int indx = 0; indx < optlen; ++indx) {
char opt = optstring.charAt(indx);
if (argv_option == opt) {
int argv_length = argv[optind].length();
if ((indx + 1 < optlen) && (optstring.charAt(indx + 1) == ':')) {
if (optind2+1 < argv_length) {
optarg = argv[optind].substring(optind2+1);
optind++;
optind2 = 1;
} else if (optind+1 < argc) {
optarg = argv[optind+1];
optind += 2;
optind2 = 1;
} else {
optarg = Character.toString(opt);
return ':';
}
} else {
if (optind2 + 1 < argv_length) {
optind2++;
} else {
optind++;
optind2 = 1;
}
}
return opt;
}
}
optarg = Character.toString(argv_option);
return '?';
}
/** Return a cmdline option argument
or the option character if command line parsing failed */
public String getOptionArg() { return optarg; }
/** Return the index of the next cmdline array element to be processed */
public int getOptionIndex() { return optind; }
public static void main(String args[])
{
getopts cmdline = new getopts(args);
char option;
while ((option = cmdline.getOption("abcd:e:")) != '') {
switch(option) {
case 'a':
case 'b':
case 'c':
System.out.println("Option='" + option + "'");
break;
case 'd':
case 'e':
System.out.println("Option='" + option +
"', Argument='" + cmdline.getOptionArg() + "'");
break;
case '?':
System.err.println("Error: Invalid option '-" +
cmdline.getOptionArg() + "'");
System.exit(1);
case ':':
System.err.println("Error: Missing option argument for '-" +
cmdline.getOptionArg() + "'");
System.exit(1);
}
}
for (int indx = cmdline.getOptionIndex(); indx < args.length; ++indx) {
System.out.println(args[indx]);
}
}
}
/*
:!javac %
:!java `basename % .java` -a abc
:!java `basename % .java` -a -b a b c
:!java `basename % .java` -ab -c a b c
:!java `basename % .java` -a -bc a b c
:!java `basename % .java` -abc arg1 arg2
:!java `basename % .java` -ddarg arg1; # error: missing option argument
:!java `basename % .java` -d darg arg1; # error: missing option argument
:!java `basename % .java` -ddarg arg1 -e earg; # error: missing option argument
:!java `basename % .java` -q; # Invalid option
:!java `basename % .java` -d; # error: missing option argument
*/
printargs.c – debugging utility for quoted strings in shell scripts
November 12, 2009
Here’s a very simple utility program that I use to debug how the shell interpreter parses quoted arguments in shell scripts. Shell quoted strings can be one of the trickiest things to get right in a script. White-space characters in filenames and directory names, string concatenation, nested single, double, back-tick quotes are only a few of the complications!
Note: To compile the code $ cc printargs.c -o printargs
Here’s an example of debugging using printargs:
$ cp $file $target
This works fine as long as the $file or $target name does not contain any white space characters. But if they do, the command will fail. For example: turn on trace ‘set -x’ and set $file=’Star Trek IV.mp4′. The trace will display ‘+ cp Star Trek IV.mp4 destdir’ which looks right, but actually is wrong. Let’s prefix the cp command with printargs to see why.
$ file=’Star Trek IV.mp4′; target=destdir
$ printargs cp $file $target
+ printargs cp Star Trek IV.mp4 destdir
1 : ‘cp’
2 : ‘Star’
3 : ‘Trek’
4 : ‘IV.mp4′
5 : ‘destdir’
The copy command is actually trying to copy three files {Star, Trek, IV.mp4} to the dest directory. It should be just one file (‘Star Trek IV.mp4′). The fix is to quote both $file and $target ie: cp “$file” “$target”.
$ file=’Star Trek IV.mp4′; target=destdir
$ printargs cp “$file” “$target”
1 : ‘cp’
2 : ‘Star Trek IV.mp4′
3 : ‘destdir’
After debugging, remove the printargs prefix from the command and the script should be good to go.
/* Name: %I%
* Synopsis: printargs -c -i -q commandline
* Description: printargs displays cmdline arguments. This is useful for debugging
* shell scripts that escape the space, backslash, quote chars ('"`)
* and other wildcard characters (eg: "[*?]").
* Options: -c Echo the command line
* -i Do not display argument indices
* -q Do not display single quotes surrounding each argument
*/
#include
#include
main(int argc, char *argv[])
{
int opt;
extern int optind;
int echo_cmdline = 0;
int display_indices = 1;
int indx;
char *quotes = "'";
char *spaces = "";
while ((opt = getopt(argc, argv, "ciq")) != EOF) {
switch(opt) {
case 'c':
echo_cmdline = 1;
break;
case 'i':
display_indices = 0;
break;
case 'q':
quotes = "";
break;
default:
fprintf(stderr, "%s: Invalid option '%c'\n", opt);
fprintf(stderr, "Syntax: %s [-ciq] command command_options command_args ..."
);
exit(1);
}
}
--argc;
if (echo_cmdline == 1) {
printf("CmdLine: ");
for (indx = optind; indx <= argc; ++indx)
printf("%s%c", argv[indx], indx < argc ? ' ' : '\n');
}
for (indx = optind; indx <= argc; ++indx) {
if (display_indices == 1)
printf("%d : ", indx - optind + 1);
printf("%s%s%s\n", quotes, argv[indx], quotes);
}
exit(0);
}
tags for OpenLink Endur/Findur AVS
November 9, 2009
Generate an index (or tag) file of AVS functions to allow these items to be easily located by a text editor (vi).
/* Synopsis: avstags [ avs_file ...]
* Description: Create vi Style tags for OpenLink Endur/Findur AVS files
*/
%{
#include
#include
#include
#include "emsg.h"
static void reset_input_line();
%}
%option noyywrap
static char *avs_filename = "";
static int braces = 0, comment = 0;
static char identifer[32 + 1], input_line[2048];
static int id_indx = 0, line_indx = 0;
static int ch, prev_ch;
static char tag[sizeof(identifer)], tag_line[sizeof(input_line)];
static int tagline_indx = 0, tag_flag = 0, tagline_flag = 0;
%%
\/\* { comment = 1; }
\*\/ { comment = 0; }
\/\/ { strcat(input_line, yytext); line_indx+= yyleng;
while ((ch = input()) != '\n')
input_line[line_indx++] = ch;
reset_input_line();
}
\{ { if (comment == 0) ++braces; input_line[line_indx++] = yytext[0]; }
\} { if (comment == 0) --braces; input_line[line_indx++] = yytext[0]; }
\" { if (comment == 0) {
ch = yytext[0];
do {
input_line[line_indx++] = ch;
prev_ch = ch;
} while (!(((ch = input()) == '"') && prev_ch != '\\'));
}
}
\( { if (comment == 0 && braces == 0) {
tagline_flag = 1;
strcpy(tag, identifer);
}
input_line[line_indx++] = yytext[0];
debug2_printf(("Matched '(' tag='%s', braces=%d, comment=%d\n", tag, braces, comment));
}
\) { input_line[line_indx++] = yytext[0];
debug2_printf(("Matched ')' tag='%s', braces=%d, comment=%d\n", tag, braces, comment));
while (comment == 0 && braces == 0 && ((ch = input()) != EOF)) {
input_line[line_indx++] = ch;
if (ch == '{') {
tag_flag = 1;
++braces;
break;
} else if (ch == ';') {
tag_flag = 0;
break;
} else if (ch == '\n') {
reset_input_line();
}
}
}
[a-zA-Z_][a-zA-Z0-9_]* {
strncpy(identifer, yytext, sizeof(identifer) - 1);
strcat(input_line, yytext);
line_indx += yyleng;
debug2_printf(("ident='%s'\n", identifer));
}
. { input_line[line_indx++] = yytext[0]; }
\n { reset_input_line(); }
%%
static void
reset_input_line()
{
debug_printf(("reset_input_line() tagline_flag=%d, tag_flag=%d, tag='%s', tag_line='%s'\n", tagline_flag, tag_flag, tag, tag_line));
if (tagline_flag)
strcpy(tag_line, input_line);
if (tag_flag) {
printf("%s\t%s\t/^%s$\n", tag, avs_filename, tag_line);
}
tagline_flag = tag_flag = 0;
memset(input_line, 0, sizeof(input_line));
line_indx = 0;
}
static void
avstags(char *filename, FILE *fp)
{
avs_filename = filename;
yyin = fp;
yylex();
}
main(int argc, char *argv[])
{
int indx;
FILE *fp;
if (argc == 1) {
avstags("", stdin);
} else {
for (indx = 1; indx tags
*/
SQL pretty printer
November 9, 2009
A very simple SQL pretty printer.
Example usage:
$ ppsql query1.sql
$ cvs co -p query.sql | ppsql
Compilation instructions:
1 $ lex ppsql.l
2 $ cc -g lex.yy.c -o ppsql
static char rev[] = "#(@) $Id: ppsql.l,v 1.8 2005/04/28 13:48:55 howard Exp $";
/* Synsopsis ppsql [file_containing_SQL_statement ...]
* Description: A simple SQL Pretty Printer
*/
%{
#include <stdio.h>
#include <string.h>
enum {
TOKEN_SELECT = 1,
TOKEN_IDENTIFIER,
TOKEN_COMMA,
TOKEN_FROM,
TOKEN_WHERE,
TOKEN_AND,
TOKEN_OR,
TOKEN_OPAREN,
TOKEN_CPAREN,
TOKEN_STRING,
TOKEN_INTEGER,
TOKEN_DOUBLE,
TOKEN_OPERATOR,
N_TOKENS
};
%}
%option noyywrap
%%
select { return TOKEN_SELECT; }
"," { return TOKEN_COMMA; }
\".*\" { return TOKEN_STRING; }
\'.*\' { return TOKEN_STRING; }
[0-9]+ { return TOKEN_INTEGER; }
[0-9]+"."[0-9]* { return TOKEN_DOUBLE; }
from { return TOKEN_FROM; }
where { return TOKEN_WHERE; }
and { return TOKEN_AND; }
or { return TOKEN_OR; }
"(" { return TOKEN_OPAREN; }
")" { return TOKEN_CPAREN; }
[a-zA-Z][a-zA-Z0-9_.]* { return TOKEN_IDENTIFIER; }
"+"|"-"|"*"|"/"|"="|""|"!="|">"|"<"|"=" {
return TOKEN_OPERATOR; }
[ \t\n]+ /* Eat Whitespace */
. printf("?%c?", yytext[0] ); /* Hmmm, what's this? */
%%
typedef enum {
BEGIN_STATE,
PARSE_SELECT,
PARSE_FROM,
PARSE_WHERE,
END_STATE,
} parse_state;
typedef struct int_stack_s {
int size;
int top;
int stack[1]; /* Actually int stack[size]; ref: new_int_stack() */
} int_stack_t;
int_stack_t *
new_int_stack(int size)
{
int_stack_t *stack;
if (stack = malloc(sizeof(int_stack_t) + (size - 1) * sizeof(int))) {
stack->size = size;
stack->top = 0;
}
return stack;
}
static int
push(int_stack_t *stack, int val)
{
if (stack->top size) {
stack->stack[stack->top++] = val;
return stack->top;
}
return -1;
}
static int
pop(int_stack_t *stack, int *val)
{
if (stack->top > 0) {
*val = stack->stack[--stack->top];
return stack->top;
}
return -1;
}
ppsql(FILE *fp_in)
{
int_stack_t *indent_stack = new_int_stack(255);
parse_state state;
int token_type, space_flag;
int indent = 0, col = 0;
yyin = fp_in;
state = BEGIN_STATE;
while (token_type = yylex()) {
switch(token_type) {
case TOKEN_SELECT:
fputs("select ", stdout);
indent = col;
col += 7;
space_flag = 0;
state = PARSE_SELECT;
break;
case TOKEN_FROM:
case TOKEN_WHERE:
case TOKEN_AND:
case TOKEN_OR:
fputc('\n', stdout);
for (col = 0; col < indent; ++col) { fputc(' ', stdout); }
if (col == 0) {
if (token_type == TOKEN_AND) {
fputs(" ", stdout);
col += 2;
} else if (token_type == TOKEN_OR) {
fputs(" ", stdout);
col += 3;
}
}
fputs(yytext, stdout);
fputc(' ', stdout);
col += (strlen(yytext) + 1);
space_flag = 0;
break;
case TOKEN_OPAREN:
if (space_flag) { fputc(' ', stdout); }
push(indent_stack, indent);
fputs("( ", stdout);
col += (2 + space_flag);
indent = col;
space_flag = 0;
break;
case TOKEN_CPAREN:
fputs(" )", stdout);
col += 2;
pop(indent_stack, &indent);
space_flag = 1;
break;
case TOKEN_COMMA:
/*fputs(((state == PARSE_SELECT) ? ",\n" : ", "), stdout);*/
fputs(", ", stdout);
col += 2;
space_flag = 0;
break;
case TOKEN_OPERATOR:
fputc(' ', stdout);
fputs(yytext, stdout);
fputc(' ', stdout);
col += (strlen(yytext) + 2);
space_flag = 0;
break;
default:
if (space_flag) { fputc(' ', stdout); }
fputs(yytext, stdout);
col += (strlen(yytext) + space_flag);
space_flag = 1;
break;
}
}
printf("\n");
return 0;
}
main( argc, argv )
int argc;
char **argv;
{
int retcode;
if (argc == 1) {
retcode = ppsql(stdin);
} else {
int indx;
FILE *fp;
for (indx = 1; indx < argc; ++indx) {
if (fp = fopen(argv[indx], "r")) {
if (argc > 2) { printf("=== %s ===\n", argv[indx]); }
retcode = ppsql(fp);
fclose(fp);
if (retcode != 0)
break;
}
}
}
return retcode;
}
/*
:!lex % && cc -g lex.yy.c && rm -f lex.yy.c
:!echo 'select col1, string, (a+b)/c, literal from table , table2 where x = y and a = b or c in (select distinct abc from def where alphabet = 1) and 1 = 1' | a.out
Sample SQL:
select distinct tran_schedule_delivery. delivery_id, 455854
from tran_schedule_delivery, ab_tran, schedule_delivery_detail
where ( tran_schedule_delivery.delivery_id = schedule_delivery_detail.delivery_id
and schedule_delivery_detail.deal_tracking_num = ab_tran.deal_tracking_num )
and ( tran_schedule_delivery.volume_type <> 0
and ( ( ab_tran.ins_type in ( select id_number
from instruments
where id_number in ( 45001, 45002, 45006, 45149, 45160 )
or base_ins_id in ( 45001, 45002, 45006, 45149, 45160 ) )
and ab_tran.buy_sell = 0 )
or ( ab_tran.ins_type in ( select id_number
from instruments
where id_number in ( 45003, 45008, 45137, 45146 )
or base_ins_id in ( 45003, 45008, 45137, 45146 ) ) )
or ( ab_tran.ins_type in ( select id_number
from instruments
where id_number in ( 45001, 45002, 45006, 45149, 45160 )
or base_ins_id in ( 45001, 45002, 45006, 45149, 45160 ) )
and ab_tran.buy_sell = 1 ) )
and tran_schedule_delivery.gmt_start_date_time &tt; '01-jan-2003 00:00:00'
and tran_schedule_delivery.volume_type in ( 4 , 6 ) )
or not exists ( select *
from query_result qr2
where qr2.unique_id = 455854
and qr2.query_result = tran_schedule_delivery.delivery_id )
*/
hexdump.c utility
November 9, 2009
Dump files out in hex format.
Useful for displaying binary files and debugging weird input/output.
Example usages:
$ hd unicode.txt
$ cat unicode.txt | hd
/* Name: $Id: hd.c,v 1.1 2003/05/02 23:56:11 howard Exp $
* Synopsis: hd file ...
* Description: Dump files in hex/ascii format.
*/
#include <stdio.h>
#include <ctype.h>
#define SEP ' '
#define SEP2 ' '
#define SEP3 " "
static void
chardump(int *buf, int len)
{
int indx = 0;
for (indx = 0; indx < len; ++indx) {
if (isprint(buf[indx]))
putchar(buf[indx]);
else
putchar('.');
}
}
static int
nibble2hex(int nibble)
{
switch(nibble) {
case 0: return '0';
case 1: return '1';
case 2: return '2';
case 3: return '3';
case 4: return '4';
case 5: return '5';
case 6: return '6';
case 7: return '7';
case 8: return '8';
case 9: return '9';
case 10: return 'A';
case 11: return 'B';
case 12: return 'C';
case 13: return 'D';
case 14: return 'E';
case 15: return 'F';
}
}
static void
hexdump(int ch)
{
putchar(nibble2hex((ch >> 4) & 0xF));
putchar(nibble2hex(ch & 0xF));
putchar(SEP);
}
static int
dump(FILE *fp)
{
int indx = 0;
int buf[16];
memset(buf, 0, sizeof(buf));
while ((buf[indx] = fgetc(fp)) != EOF) {
hexdump(buf[indx++]);
if (indx == 8)
putchar(SEP2);
else if (indx == 16) {
fputs(SEP3, stdout);
chardump(buf, indx);
putchar('\n');
indx = 0;
}
}
if (indx > 0) {
int indx2;
for (indx2 = indx; indx2 < 16; ++indx2) {
if (indx2 == 8) { putchar(SEP2); }
putchar(' '); putchar(' '); putchar(SEP);
}
fputs(SEP3, stdout);
chardump(buf, indx);
putchar('\n');
}
return 0;
}
main(int argc, char *argv[])
{
int indx;
FILE *fp;
if (argc == 1) {
dump(stdin);
} else {
for (indx = 1; indx < argc; ++indx) {
if (fp = fopen(argv[indx], "rb")) {
dump(fp);
fclose(fp);
}
}
}
exit(0);
}
/*
:!cc % -o hd
:!gcc -g % -o hd
*/
grep utilities: hgrep (highlighted grep) and rgrep (recursive grep)
November 9, 2009
1. hgrep displays grep results in highlights.
2. rgrep runs grep on all the files in a directory tree.
Example usage:
$ hgrep main *.c; # Search for main in all C files
$ rgrep -e ‘[Ff]lour’ -e cornstarch $HOME/recipes; # Search all files in the recipes directory for flour or cornstarch
— hgrep —
#! /bin/sh
# Synopsis: hgrep pattern file ...
# Description: Hilighted grep
smso=`tput smso`
rmso=`tput rmso`
pattern="$1"; shift
grep "$pattern" "$@" | sed -e "s@\(${pattern}\)@${smso}\1${rmso}@"
— rgrep —
#! /bin/sh
# Name: $Id: rgrep,v 1.1 2009/10/11 20:37:21 hhong Exp $
# Synopsis: rgrep pattern directory ...
# Synopsis: rgrep [-e pattern ...] pattern directory ...
# Description: Run grep on all the files of a directory tree
while getopts e:i opt; do
case $opt in
e) pattern="$pattern -e '$OPTARG'";;
i) ignorecase='-i';;
esac
done
shift `expr $OPTIND - 1`
if [ -z "$pattern" ]; then
pattern="'$1'"; shift
fi
for arg; do
if [ ! -d "$arg" ]; then
echo "$0: Error '$arg' is not a directory." >&2
exit 1
fi
done
find "$@" -type d -print | while read dir; do
edir=`ls -A "$dir"`
if [ -n "$edir" ]; then # Check for empty directory
# Use eval in case $pattern or $dir contain whitespace characters
eval grep $ignorecase $pattern "'$dir'/*" /dev/null;
fi
done
Number base conversions and calculations
November 9, 2009
Perform number base conversions and calculations.
Note: The script behaves differently, depending on the filename (the executable may still be the same file). The following hard-links ($ ln math.sh …) to the math.sh script provides the following shortcuts…
- x2d (hex to decimal), x2o (hex to octal), x2b (hex to binary)
- d2x (decimal to hex), d2o (decimal to octal), d2b (decimal to binary)
- o2x (octal to hex), o2d (octal to decimal), o2b (octal to binary)
- b2x (binary to hex), b2d (binary to decimal), b2o (binary to octal)
Example usage:
$ d2x; # (Interactive) decimal to hex conversions
$ x2d a b c d e f 10/2
$ echo ‘f+1 ff+2′ | x2d
#! /bin/sh
# Synopsis: Math.sh [-i inputbase] [-o outputbase] [math-expression | Number] ...
# Description: Math.sh performs base number conversions, and 'bc -l' calculations
# Note1: Spaces should be avoided in math-expressions. A space character in
# an expression may be intepreted as a command line field separator.
# Note2: Renaming or (hard/symbolic) ln'ing to the script alters the default input
# and output base (ie: b2o,b2d,b2x, o2b,o2d,o2x, d2b,d2o,d2x, x2b,x2d,x2d)
# (b=binary, o=octal, d=decimal, x=hexadecimal)
# Example Usage: $ math.sh; # Interactive decimal calculator
# $ math.sh '1.11111111^2'
# $ echo 'ff ff+1' | x2d
obase=10
ibase=10
case $0 in
*b2o) ibase=2; obase=8;;
*b2d) ibase=2; obase=10;;
*b2x) ibase=2; obase=16;;
*o2b) ibase=8; obase=2;;
*o2d) ibase=8; obase=10;;
*o2x) ibase=8; obase=16;;
*d2b) ibase=10; obase=2;;
*d20) ibase=10; obase=8;;
*d2x) ibase=10; obase=16;;
*x2b) ibase=16; obase=2;;
*x2o) ibase=16; obase=8;;
*x2d) ibase=16; obase=10;;
*[Mm]ath*)
while getopts i:o: opt; do
case "$opt" in
i) ibase=$OPTARG;;
o) obase=$OPTARG;;
esac
done
shift `expr $OPTIND - 1`
;;
esac
{
echo "obase=$obase"
echo "ibase=$ibase"
if [ $# -eq 0 ]; then
cat
else
echo "$*"
fi | tr 'a-f ' 'A-F\n'
} | bc -l
ffpath — – Search $PATH for file(s)
November 2, 2009
This is a utility script that operates similarly to the find file (ff.sh) script previously presented. But instead of searching a directory tree, it searches the components of a $PATH environment variable.
Example usage:
$ ffpath javac jdb; # Find the Java compiler and debugger
$ ffpath -m myscript1 myscript2; # Display the myscript1 and myscript2 scripts using more
$ ffpath -v PERL5LIB -s’;’ -e ‘pod2text’ sybdbi.pm; # Find and convert the Sybase DBi Perl doc to text
#! /bin/sh
# Name: $Id: ffpath,v 1.4 2008/10/09 12:18:51 hhong Exp $
# Synopsis: ffpath.sh [-v envvar] [-s field_separator] [-[l1cm]] file ...
# Description: Search $PATH for file(s)
# Options: -v envvar Specify environment variable
# -s fs Use 'fs' for the directory field separator
# -l list file info using 'ls -l' long format (default)
# -1 list one file per line ie: 'ls -1'
# -c Use 'cat' to display the file
# -m Use 'more' to display the file
# -e prog Run 'prog' on file
while getopts v:s:l1cme: opt; do
case "$opt" in
v) envvar=$OPTARG;;
s) sep=$OPTARG;;
l) display='lsl';;
1) display='ls1';;
c) display='cat';;
m) display='more';;
e) display='exec'; exec=$OPTARG;;
\?) exit 1;;
esac
done
shift `expr $OPTIND - 1`
for file; do
eval echo \$${envvar:-PATH} | tr {$sep:-:} '\n' | while read dir; do
if [ -f "$dir/$file" ]; then
case "${display:-lsl}" in
ls1) ls -1 "$dir/$file";;
lsl) ls -l "$dir/$file";;
echo) echo "$dir/$file";;
cat) cat "$dir/$file";;
more) less -rXe "$dir/$file";;
exec) eval $exec "$dir/$file";;
esac
fi
done
done
Some neat aliases, shell functions, and shell one-liners
October 30, 2009
- Set the command line prompt to the current shell level and directory (directory is abbreviated if very long)
chdir () { if [ $# -eq 2 ]; then 'cd' `pwd | sed -e "s@$1@$2@"`; else 'cd' "$@"; fi && { if [ "${PWD#/*/*/}" = "$PWD" ]; then PS1='[${SHLVL} $PWD] '; else PS1='[${SHLVL} ..${PWD#${PWD%/*/*}}] '; fi; case "$TERM" in xterm) echo -ne "33]0;${PWD}07" ;; esac } }Note: add the following alias and environment variable to your $HOME/.profile script:
alias cd=’chdir’
SHLVL=0; # for ksh only, also requires ‘(( SHLVL = $SHLVL + 1 ))’ in the ~/.kshrc startup script - Pipe the output of a command in to an editor (vi) instead of using more or less.
function vip { tmpfile="$HOME/.tmp/$$.vip" trap "rm -f $tmpfile" 0 9 15 cat > $tmpfile vi $tmpfile < /dev/tty > /dev/tty }Note: Requires the $HOME/.tmp directory.
Example usage: $ ls -l | vip - Display the exit code of a program.
trap "echo ' ' Retcode=\$?" ERR
Note: Add to your .bashrc or .kshrc startup script
- List all sub-directories of a specified directory:
lld () { if [ $# -eq 0 ]; then ls -ld */; else for d in "$@"; do ls -ld ${d:-.}/*/; done; fi }Example usage:
$ lsdirs; # display list of subdirectories in the current working directory
$ lsdirs /usr/local $HOME/logs - Copy a directory tree to a remote system:
$ { cd source_dir; tar cvf - .; } | ssh remote_host '{ cd dest_dir; tar xvf -; } - A simplified logfile rolling scheme. Remove all ‘xyz’ log files, except the last $keep files sorted by last modified date. Add to cron for automation.
$ ls -1t "$logdir/xyz.*.log" | sed -e "1,${keep}d" | xargs -d'\n' rm
File Find
October 28, 2009
Here’s a shell script that implements the old Norton Utilities “FileFind” utility. I added a couple of useful additional options.
- ‘-l’ will display a detailed file listing ala ‘ls -l file’.
- ‘-c’ and ‘-m’ will display the file using cat and ‘more’ respectively.
- ‘-e’ option will execute a program on the found file(s).
Example usage:
$ ff. notes.txt; # find the notes.txt file
$ ff. -m notes.txt; # display the notes.txt file
$ ff. -e ‘grep footnote /dev/null’ notes.txt; # grep footnotes from notes.txt files
#! /bin/sh
# Synopsis: ff. [-lcm] [-e program] filename ...
# Description: find files.
# Options: -l display directory long listing of file
# -c cat the file
# -m display the file using 'more' (or less)
# -e execute 'program' on the file
while getopts lcme: opt; do
case "$opt" in
l) print='-exec ls -l {} \;';;
c) print='-exec cat {} \;';;
m) print='-exec less -E {} \;';;
e) print="-exec $OPTARG {} \;";;
\?) exit 1;;
esac
done
shift `expr $OPTIND - 1`
names="-name $1"; shift
for f; do
names="-name $f -o $names "
done
eval find . '\(' $names '\)' ${print:--print}
A safe rm
October 27, 2009
Here is a script that implements a Windows style ‘Recycle Bin’ delete function. Similarly like Windows delete, it moves deleted files/directories to a temporary directory (default: $HOME/.tmp). After a file is moved to the tmp directory and has not been accessed for N days, it is permanently deleted the next time the rm command is run (think of this as an automated ‘empty recycle bin’ function). It implements all the ‘rm’ options making it an ideal replacement for the /bin/rm command in interactive use.
Example usage:
$ alias rm=$HOME/bin/rm
#! /bin/sh # Synopsis: rm [-fir] file ... # Description: A Safe rm (move file(s) to a tmp directory for later deletion). Files in # the tmp directory that have not been accessed in N days are permantly deleted # the next time the rm command is run. # Options: -f (force) Run "/bin/rm" instead of moving files to the tmpdir # -i interactive mode # -r move (recursively) a directory tree to the tmp directory # Caveat: mv fails if the filename matches a directory name in the $tmpdir directory. #set -x tmpdir=$HOME/.tmp while getopts fir opt; do case $opt in f) force="-f";; i) interactive="-i";; r) recursive="-r";; \?) exit 1;; esac done shift `expr $OPTIND - 1` if [ "$force" ]; then # Run /bin/rm if '-f' is specified! /bin/rm -f $interactive $recursive "$@"; # This is useful in shell functions exit $? # when you want the real rm executable for file; do if [ -n "$interactive" ]; then echo -n "remove '${file}'? " read yn if [ "$yn" != "Y" -a "$yn" != "y" ]; then continue fi fi if [ -d "$file" ]; then if [ -n "$recursive" ]; then mv -f "$file" "$tmpdir" || retcode=2 else echo "$0: cannot remove '$file': Is a directory" retcode=1 fi continue fi bf=`basename "$file"` mv -f "$file" "$tmpdir" touch "$tmpdir/$bf"; # For post cleanup, $file will be deleted N days from today done # Prolog: Clean up files, permanently delete files after atime days have elapsed { /bin/find "$tmpdir" -type f -atime +7 -exec /bin/rm '{}' \; /bin/find "$tmpdir" -mindepth 1 -type d -exec rmdir '{}' \; 2>/dev/null } & exit ${retcode:-0}