2 # Copyright (C) 2014-2016 Ian Kelling
3 # This program is under GPL v. 3 or later, see <http://www.gnu.org/licenses/>
7 lnf -T TARGET LINK_NAME (1st form)
9 lnf TARGET... DIRECTORY (3rd form)
10 Create symlinks forcefully
12 Removes existing files using trash-put or rm -rf if it is not available,
13 or trash-put fails due to a limitation such as a cross-filesystem link.
14 Create directory if needed. Slightly more restrictive arguments than ln.
16 In the 1st form, create a link to TARGET with the name LINK_NAME. In the 2nd
17 form, create a link to TARGET in the current directory. In the 3rd form, create
18 links to each TARGET in DIRECTORY.
20 Do export LNF_VERBOSE=true for verbose output
23 if [[ $1 == --help ||
$1 == -h ||
$# -eq 0 ]]; then
29 if [[ $1 == -T ]]; then
32 if (( $# != 2 )); then
33 echo "lnf error: expected 2 arguments with -T flag. Got $#"
39 local reset_extglob
=false
40 ! shopt extglob
>/dev
/null
&& reset_extglob
=true
44 local x ret prefix dir to_remove
50 dest_dir
="$(dirname "$dest_file")"
51 if [[ -e $dest_file ||
-L $dest_file ]]; then
52 to_remove
+=("$dest_file")
53 elif [[ ! -d $dest_dir ]]; then
55 if [[ -e $dest_dir ||
-L $dest_dir ]]; then
59 elif (( $# >= 2 )); then
61 if [[ -d $dest_dir ]]; then
62 prefix
="$dest_dir/" # last arg
63 for x
in "${@:1:$(( $# - 1 ))}"; do # all but last arg
64 # Remove 1 or more trailing slashes, using.
66 # remove any leading directory components, add prefix
68 [[ -e "$x" ||
-L "$x" ]] && to_remove
+=("$x")
73 elif [[ $# -eq 1 ]]; then
74 [[ -e "${1##*/}" || -L "${1##*/}" ]] && to_remove+=("${1##*/}")
76 if (( ${#to_remove[@]} >= 1 )); then
77 if type -P trash-put
>/dev
/null
; then
78 if [[ $LNF_VERBOSE == true
]]; then
79 echo "lnf: trash-put -- ${to_remove[*]}"
81 trash-put
-- "${to_remove[@]}" || ret
=$?
82 # trash-put will fail to trash a link that goes across filesystems (72),
83 # and for empty files (74)
84 # so revert to rm -rf in that case
85 if [[ $ret == 72 ]]; then
86 echo "$0: using rm -rf to overcome cross filesystem trash-put limitation"
87 rm -rf -- "${to_remove[@]}"
88 elif [[ $ret == 74 ]]; then
89 echo "$0: using rm -rf to overcome empty file & hardlink trash-put limitation"
90 rm -rf -- "${to_remove[@]}"
91 elif [[ $ret && $ret != 0 ]]; then
95 if [[ $LNF_VERBOSE == true
]]; then
96 echo "lnf: rm -rf -- ${to_remove[*]}"
98 rm -rf -- "${to_remove[@]}"
102 $reset_extglob && shopt -u extglob
105 if ! mkdir
-p "$dest_dir"; then
106 echo "lnf error: failed to make directory $dest_dir"