#!/usr/bin/env sh set -e 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 die() { fmt=$1 shift printf "nextbin %s failed: $fmt\n" "$orig_exe" "$@" >&2 exit 1 } [ -n "$PATH" ] || die 'PATH is empty' # shellcheck disable=SC3013 if [ / -ef / ] && ! [ / -ef /dev/null ]; then same_file() { # shellcheck disable=SC3013 [ "$1" -ef "$2" ] } else if command -v bash >/dev/null 2>&1; then exec bash "$0" "$orig_exe" "$@" fi ino() { ls=$(ls -i "$1") printf '%s\n' "${ls%% *}" } dev() { df -P "$1" | awk 'END{print $1}' } same_file() { [ "$(ino "$1")" = "$(ino "$2")" ] && [ "$(dev "$1")" = "$(dev "$2")" ] } fi case $orig_exe in /*) ;; *) die 'non-absolute $0' esac exe_name=${orig_exe##*/} path=$PATH phase=1 found= while :; do exe=${path%%:*}/$exe_name if [ -f "$exe" ] && [ -x "$exe" ]; then if [ "$phase" = 1 ]; then if same_file "$exe" "$orig_exe"; then phase=2 fi elif same_file "$exe" "$orig_exe"; then [ -z "$found" ] || die 'duplicate PATH entries found' elif [ -z "$found" ]; then found=$exe fi fi case $path in *:*) path=${path#*:} ;; *) break ;; esac done if [ "$phase" = 1 ]; then found=$(command -v "$exe_name") || die '%s is not in PATH' "$exe_name" elif [ -z "$found" ]; then die '%s is last instance' "$orig_exe" fi "$action" "$found" "$@"