#!/bin/bash # Copyright (C) 2014-2016 Ian Kelling # This program is under GPL v. 3 or later, see lnf() { local help="Usage: lnf -T TARGET LINK_NAME (1st form) lnf TARGET (2nd form) lnf TARGET... DIRECTORY (3rd form) Create symlinks forcefully 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." if [[ $1 == --help || $# -eq 0 ]]; then echo "$help" return 0 fi local nodir if [[ $1 == -T ]]; then nodir=-T shift if (( $# != 2 )); then echo "lnf error: expected 2 arguments with -T flag. Got $#" return 1 fi fi local reset_extglob=false ! shopt extglob >/dev/null && reset_extglob=true shopt -s extglob local x ret prefix dir to_remove local mkdir=false to_remove=() if [[ $nodir ]]; then 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 prefix="${!#}/" # last arg for x in "${@:1:$(( $# - 1 ))}"; do # all but last arg # Remove 1 or more trailing slashes, using. x="${x%%+(/)}" # remove any leading directory components, add prefix x="$prefix/${x##*/}" [[ -e "$x" || -L "$x" ]] && to_remove+=("$x") done else if ! mkdir -p "${!#}"; then echo "lnf error: failed to make directory ${!#}" return 1 fi fi elif [[ $# -eq 1 ]]; then [[ -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 ln -s $nodir -- "$@" } lnf "$@"