• 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
Advertisements

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}