add -h arg for help
[lnf] / lnf
diff --git a/lnf b/lnf
index 29f137df5f89acaa63075826a3801c2cf5333569..2518c1c4ac60cf35147ba72bdc886c252759bbe2 100755 (executable)
--- a/lnf
+++ b/lnf
@@ -1,22 +1,23 @@
 #!/bin/bash
 #!/bin/bash
-# Copyright (C) 2014 Ian Kelling
+# Copyright (C) 2014-2016 Ian Kelling
 # This program is under GPL v. 3 or later, see <http://www.gnu.org/licenses/>
 
 lnf() {
 # This program is under GPL v. 3 or later, see <http://www.gnu.org/licenses/>
 
 lnf() {
-    local help="lnf - Create symlinks conveniently and forcefully.
-Usage:
+    local help="Usage:
        lnf -T TARGET LINK_NAME     (1st form)
        lnf TARGET                  (2nd form)
        lnf TARGET... DIRECTORY     (3rd form)
        lnf -T TARGET LINK_NAME     (1st form)
        lnf TARGET                  (2nd form)
        lnf TARGET... DIRECTORY     (3rd form)
+Create symlinks forcefully
 
 
-Remove existing file in the using trash-put or rm -rf if it is not available.
+Removes existing files using trash-put or rm -rf if it is not available,
+or trash-put fails due to a limitation such as a cross-filesystem link.
 Create directory if needed. Slightly more restrictive arguments than ln.
 
 In the 1st form, create a link to TARGET with the name LINK_NAME.  In the 2nd
 form, create a link to TARGET in the current directory.  In the 3rd form, create
 links to each TARGET in DIRECTORY."
 Create directory if needed. Slightly more restrictive arguments than ln.
 
 In the 1st form, create a link to TARGET with the name LINK_NAME.  In the 2nd
 form, create a link to TARGET in the current directory.  In the 3rd form, create
 links to each TARGET in DIRECTORY."
-    
-    if [[ $1 == --help || $# -eq 0 ]]; then
+
+    if [[ $1 == --help || $1 == -h || $# -eq 0 ]]; then
         echo "$help"
         return 0
     fi
         echo "$help"
         return 0
     fi
@@ -30,38 +31,36 @@ links to each TARGET in DIRECTORY."
             return 1
         fi
     fi
             return 1
         fi
     fi
-    
+
     local reset_extglob=false
     ! shopt extglob >/dev/null && reset_extglob=true
     shopt -s extglob
 
     local reset_extglob=false
     ! shopt extglob >/dev/null && reset_extglob=true
     shopt -s extglob
 
-    
-    local remove x
-    if type -P trash-put >/dev/null; then
-        remove=trash-put
-    else
-        remove="rm -rf"
-    fi
-    
+
+    local x ret prefix dir to_remove
+    local mkdir=false
+
+    to_remove=()
     if [[ $nodir ]]; then
     if [[ $nodir ]]; then
-        if [[ -e "$2" || -L "$2" ]]; then
-            $remove "$2"
-        elif ! mkdir -p "$(dirname "$2")"; then
-            echo "lnf error: failed to make directory $(dirname "$2")"
-            return 1
+        dir="$(dirname "$2")"
+        if [[ -e $2 || -L $2 ]]; then
+            to_remove+=("$2")
+        elif [[ ! -d $dir ]]; then
+            mkdir=true
+            if [[ -e $dir || -L $dir ]]; then
+                to_remove+=("$dir")
+            fi
         fi
     elif (( $# >= 2 )); then
         if [[ -d ${!#} ]]; then
         fi
     elif (( $# >= 2 )); then
         if [[ -d ${!#} ]]; then
-            local oldcwd=$PWD
-            cd "${!#}" # last arg
+            prefix="${!#}/" # last arg
             for x in "${@:1:$(( $# - 1 ))}"; do # all but last arg
             for x in "${@:1:$(( $# - 1 ))}"; do # all but last arg
-                # remove any trailing slashes, uses extglob
+                # Remove 1 or more trailing slashes, using.
                 x="${x%%+(/)}"
                 x="${x%%+(/)}"
-                # remove any leading directory components
-                x="${x##*/}"
-                [[ -e "$x" || -L "$x" ]] && $remove "$x"
+                # remove any leading directory components, add prefix
+                x="$prefix/${x##*/}"
+                [[ -e "$x" || -L "$x" ]] && to_remove+=("$x")
             done
             done
-            cd "$oldcwd"
         else
             if ! mkdir -p "${!#}"; then
                 echo "lnf error: failed to make directory ${!#}"
         else
             if ! mkdir -p "${!#}"; then
                 echo "lnf error: failed to make directory ${!#}"
@@ -69,10 +68,37 @@ links to each TARGET in DIRECTORY."
             fi
         fi
     elif  [[ $# -eq 1 ]]; then
             fi
         fi
     elif  [[ $# -eq 1 ]]; then
-        [[ -e "${1##*/}" || -L "${1##*/}" ]] && $remove "${1##*/}"
+        [[ -e "${1##*/}" || -L "${1##*/}" ]] && to_remove+=("${1##*/}")
+    fi
+    if (( ${#to_remove[@]} >= 1 )); then
+        if type -P trash-put >/dev/null; then
+            trash-put -- "${to_remove[@]}" || ret=$?
+            # trash-put will fail to trash a link that goes across filesystems (72),
+            # and for empty files (74)
+            # so revert to rm -rf in that case
+            if [[ $ret == 72 ]]; then
+                echo "$0: using rm -rf to overcome cross filesystem trash-put limitation"
+                rm -rf -- "${to_remove[@]}"
+            elif [[ $ret == 74 ]]; then
+                echo "$0: using rm -rf to overcome empty file & hardlink trash-put limitation"
+                rm -rf -- "${to_remove[@]}"
+            elif [[ $ret && $ret != 0 ]]; then
+                return $x
+            fi
+        else
+            rm -rf -- "${to_remove[@]}"
+        fi
+    fi
+
+    $reset_extglob && shopt -u extglob
+
+    if $mkdir; then
+        if ! mkdir -p "$(dirname "$2")"; then
+            echo "lnf error: failed to make directory $(dirname "$2")"
+            return 1
+        fi
     fi
 
     fi
 
-    $reset_extglob && shopt -u extglob 
     ln -s $nodir -- "$@"
 }
 lnf "$@"
     ln -s $nodir -- "$@"
 }
 lnf "$@"