#!/bin/sh # link tree lt_version='lt-0.1' unset CDPATH export LC_ALL=C IFS=' ' help() { echo "Lt is a tool for creating link trees. Usage: lt [-Vn] src dest Options: -V print version and exit -n print actions but not execute" } # ca returns the common ancestor between 2 paths # i.e. ca /h/u/a/b /h/u/c/d => /h/u ca() { ca_p1=${1#/} ca_p2=${2#/} ca_r1='' ca_r2='' R1=/ while true; do [ "$ca_p1" ] || [ "$ca_p2" ] || break ca_r1=$ca_r1/${ca_p1%%/*} ca_p1=${ca_p1#*/} ca_r2=$ca_r2/${ca_p2%%/*} ca_p2=${ca_p2#*/} [ "$ca_r1" != "$ca_r2" ] && break R1=$ca_r1 done } # pp returns the relative path from child to parent # i.e. pp /h/u/a /h/u => .. pp() { pp_s=$1 pp_b=$2 R1='' while true; do [ "$pp_b" = "$pp_s" ] && break pp_s=${pp_s%/*} [ "$R1" ] && R1=$R1/.. || R1=.. done } # rp returns the relative path between src and base # i.e. rp /h/u/a/b/f /h/u/b/f [/h/u] ../a/b/f rp() { rp_s=$1 rp_d=$2 rp_c=$3 ! [ "$rp_c" ] && ca "$1" "$2" && rp_c=$R1 rp_bs=${rp_s#$rp_c/} pp "$rp_d" "$rp_c" && R1=$R1/$rp_bs && R1=${R1#../} } skip=".git .gitignore .*.swp Makefile README.md" # lt links src tree to dest (each file is a link) lt() { d=$(mkdir -p "$2" && cd "$2" && pwd) cd "$1" && s=$PWD && find . ! -type d -print | { cd "$d" && while read -r f; do for k in $skip; do case $f in (./$k|./$k/*) continue 2;; esac done f=${f#./}; fd=$d/$f; fd=${fd%/*} test -d "$fd" || $trace mkdir -p "$fd" rp "$s/$f" "$d/$f" && $trace ln -sf "$R1" "$d/$f" done } } while getopts :nvV opt; do case $opt in (n) trace='echo' ;; (V) echo "$lt_version"; exit ;; (*) help; exit 1;; esac done shift $((OPTIND -1)) lt "$1" "$2" #echo $1 $2 $3 && $1 $2 $3 && echo $R1 # Shell coding style: # - standard POSIX shell, to be used as-is on Unix, Linux (busybox), *BSD* # - no bashism, GNUism, etc. # - local variables in same process are prefixed with function name, to avoid collisions # - same process functions return values in R1, R2, ... global vars. # - self-documented, self-tested