#!/bin/sh set -e die() { fmt=$1 shift printf "nextbin %s failed: $fmt\n" "$orig_exe" "$@" >&2 exit 1 } usage() { # shellcheck disable=SC2016 echo 'usage: nextbin [-v] "$0" "$@"' >&2 } case "$1" in -v) action="echo"; shift;; -*|'') usage; exit 1;; *) action="exec" esac orig_exe=$1 shift exe_name=${orig_exe##*/} [ -n "$PATH" ] || die 'PATH is empty' case "$orig_exe" in */) die 'ends with /' ;; */*) orig_dir=${orig_exe%/*} ;; *) # either shell has not resolved script-file into a path, or script is # in cwd and PATH has . or empty entries if ! [ -d "$orig_exe" ] && [ -x "$orig_exe" ]; then case ":$PATH:" in *::*:.:*|*:.:*::*) die 'exe in cwd and PATH has both . and empty entries' ;; *::*) orig_dir= ;; *:.:*) orig_dir=. ;; *) die 'missing /' esac fi esac tmp_path=:$PATH: new_path=${tmp_path#*:$orig_dir:} [ -n "$new_path" ] \ || die '%s is last PATH entry' "$orig_dir" if [ "$new_path" != "$tmp_path" ]; then new_path_2=${new_path#*:$orig_dir:} [ "$new_path" = "$new_path_2" ] \ || die 'duplicate entry in PATH: %s' \ "$orig_exe" "$orig_dir" else # try to find equivalent path found_alt_dir= new_orig_dir= equiv_orig_dir=$(cd "${orig_dir:-.}" && pwd -L) tmp_path_2=$PATH while :; do p=${tmp_path_2%%:*} if [ "$(cd "$p" >/dev/null 2>&1 && pwd -L)" = "$equiv_orig_dir" ]; then [ -z "$found_alt_dir" ] \ || die "duplicate equivalent path in PATH: '%s' = '%s'" \ "$new_orig_dir" "$p" found_alt_dir=1 new_orig_dir=$p fi case "$tmp_path_2" in *:*) tmp_path_2=${tmp_path_2#*:};; *) break esac done if [ -n "$found_alt_dir" ]; then new_path=${tmp_path#*:$new_orig_dir:} [ -n "$new_path" ] \ || die '%s is last PATH entry' "$new_orig_dir" else new_path=$PATH: fi fi exe=$(PATH="${new_path%:}" command -v "$exe_name") || true [ -n "$exe" ] \ || die 'PATH lookup failed using %s' \ "${new_path%:}" $action "$exe" "$@"