LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Blogs > konsolebox
User Name
Password

Notices



Rate this Entry

Getting Absolute Paths of UNIX Directories and Filenames in Shell Scripts

Posted 07-08-2011 at 04:05 AM by konsolebox
Updated 07-17-2011 at 10:11 AM by konsolebox
Tags bash, ksh, script, shell, zsh

This post is a compilation of the function getabspath() for different shells that can be used to get the absolute form of a path. The function accepts an argument path then returns the absolute form of it to the variable $__.

bash (3.0 and newer only)
Code:
function getabspath {
	local -a T1 T2
	local -i I=0
	local IFS=/ A

	case "$1" in
	/*)
		read -r -a T1 <<< "$1"
		;;
	*)
		read -r -a T1 <<< "/$PWD/$1"
		;;
	esac

	T2=()

	for A in "${T1[@]}"; do
		case "$A" in
		..)
			[[ I -ne 0 ]] && unset T2\[--I\]
			continue
			;;
		.|'')
			continue
			;;
		esac

		T2[I++]=$A
	done

	case "$1" in
	*/)
		[[ I -ne 0 ]] && __="/${T2[*]}/" || __=/
		;;
	*)
		[[ I -ne 0 ]] && __="/${T2[*]}" || __=/.
		;;
	esac
}
bash (2.05b and newer only)
Code:
function getabspath {
	local -a T=()
	local -i I=0
	local IFS=/ A

	case "$1" in
	/*)
		__=$1
		;;
	*)
		__=/$PWD/$1
		;;
	esac

	while read -r -d / A; do
		case "$A" in
		..)
			[[ I -ne 0 ]] && unset T\[--I\]
			continue
			;;
		.|'')
			continue
			;;
		esac

		T[I++]=$A
	done <<< "$__/"

	case "$1" in
	*/)
		[[ I -ne 0 ]] && __="/${T[*]}/" || __=/
		;;
	*)
		[[ I -ne 0 ]] && __="/${T[*]}" || __=/.
		;;
	esac
}
bash (all stable versions)
Code:
function getabspath {
	local -a T=()
	local -i I=0
	local IFS=/ A

	case "$1" in
	/*)
		__=$1
		;;
	*)
		__=/$PWD/$1
		;;
	esac

	while read -r -d / A; do
		case "$A" in
		..)
			[[ I -ne 0 ]] && unset T\[--I\]
			continue
			;;
		.|'')
			continue
			;;
		esac

		T[I++]=$A
	done << .
$__/
.

	case "$1" in
	*/)
		[[ I -ne 0 ]] && __="/${T[*]}/" || __=/
		;;
	*)
		[[ I -ne 0 ]] && __="/${T[*]}" || __=/.
		;;
	esac
}
ksh (original)
Code:
if
	__=.
	read __ <<< "$__"
	[[ $__ = '"."' ]]
then
	function getabspath {
		typeset T1 T2
		typeset -i I=0
		typeset IFS=/ A

		case "$1" in
		/*)
			read -r -A T1 <<< $1
			;;
		*)
			read -r -A T1 <<< $PWD/$1
			;;
		esac

		set -A T2

		for A in "${T1[@]}"; do
			case "$A" in
			..)
				[[ I -ne 0 ]] && unset T2\[--I\]
				continue
				;;
			.|'')
				continue
				;;
			esac

			T2[I++]=$A
		done

		case "$1" in
		*/)
			[[ I -ne 0 ]] && __="/${T2[*]}/" || __=/
			;;
		*)
			[[ I -ne 0 ]] && __="/${T2[*]}" || __=/.
			;;
		esac
	}
else
	function getabspath {
		typeset T1 T2
		typeset -i I=0
		typeset IFS=/ A

		case "$1" in
		/*)
			read -r -A T1 <<< "$1"
			;;
		*)
			read -r -A T1 <<< "$PWD/$1"
			;;
		esac

		set -A T2

		for A in "${T1[@]}"; do
			case "$A" in
			..)
				[[ I -ne 0 ]] && unset T2\[--I\]
				continue
				;;
			.|'')
				continue
				;;
			esac

			T2[I++]=$A
		done

		case "$1" in
		*/)
			[[ I -ne 0 ]] && __="/${T2[*]}/" || __=/
			;;
		*)
			[[ I -ne 0 ]] && __="/${T2[*]}" || __=/.
			;;
		esac
	}
fi
pdksh
Code:
getabspath() {
	typeset A T IFS=/ TOKENS I=0 J=0

	A=${1%/}

	if [[ -n $A ]]; then
		while :; do
			T=${A%%/*}

			case "$T" in
			..)
				if [[ I -gt 0 ]]; then
					unset TOKENS\[--I\]
				else
					(( ++J ))
				fi
				;;
			.|'')
				;;
			*)
				TOKENS[I++]=$T
				;;
			esac

			case "$A" in
			*/*)
				A=${A#*/}
				;;
			*)
				break
				;;
			esac
		done
	fi

	__="/${TOKENS[*]}"

	if [[ $1 != /* ]]; then
		A=${PWD%/}

		while [[ J -gt 0 && -n $A ]]; do
			A=${A%/*}
			(( --J ))
		done

		[[ -n $A ]] && __=$A${__%/}
	fi

	if [[ $__ = / ]]; then
		[[ $1 != */ ]] && __=/.
	elif [[ $1 == */ ]]; then
		__=$__/
	fi
}
zsh
Code:
function getabspath {
	local -a TOKENS; set -A TOKENS
	local -i I=0
	local IFS=/ T

	__=$1

	case "$1" in
	/*)
		set -- ${=1}
		;;
	*)
		set -- ${=PWD} ${=1}
		;;
	esac

	for T; do
		case "$T" in
		..)
			[[ I -ne 0 ]] && TOKENS[I--]=()
			continue
			;;
		.|'')
			continue
			;;
		esac

		TOKENS[++I]=$T
	done

	case "$__" in
	*/)
		[[ I -ne 0 ]] && __="/${TOKENS[*]}/" || __=/
		;;
	*)
		[[ I -ne 0 ]] && __="/${TOKENS[*]}" || __=/.
		;;
	esac
}
any other shell based from the original sh
Code:
# first version - assuming the script doesn't mind 'set -f' being set

getabspath() {
	case "$1" in
	/*)
		__=$1
		;;
	*)
		__=`exec pwd`/$1
		;;
	esac

	set -f
	IFS=/
	set -- $__

	while :; do
		__='' __L=''

		for __A; do
			shift

			case "$__A" in
			..)
				[ -z "$__L" ] && continue
				shift "$#"
				set -- $__ "$@"
				continue 2
				;;
			.|'')
				continue
				;;
			esac

			[ -n "$__L" ] && __=$__/$__L
			__L=$__A
		done

		__=$__/$__L

		break
	done

	unset __A __L

	case "$1" in
	*/)
		[ ! "$__" = / ] && __=$__/
		;;
	*)
		[ "$__" = / ] && __=/.
		;;
	esac
}

# 2nd version - encapsulates settings inside a subshell

getabspath() {
	case "$1" in
	/*)
		__=$1
		;;
	*)
		__=`exec pwd`/$1
		;;
	esac

	__=`
		set -f
		IFS=/
		set -- $__

		while :; do
			__='' L=''

			for A; do
				shift

				case "$A" in
				..)
					[ -z "$L" ] && continue
					shift "$#"
					set -- $__ "$@"
					continue 2
					;;
				.|'')
					continue
					;;
				esac

				[ -n "$L" ] && __=$__/$L
				L=$A
			done

			__=$__/$L

			break
		done

		echo "$__"
	`

	case "$1" in
	*/)
		[ ! "$__" = / ] && __=$__/
		;;
	*)
		[ "$__" = / ] && __=/.
		;;
	esac
}

# 3rd version - try to make things run faster; prevent it from reparsing commands

getabspath() {
	case "$1" in
	/*)
		__=$1
		;;
	*)
		__=`exec pwd`/$1
		;;
	esac

	__=`getabspath_`

	case "$1" in
	*/)
		[ ! "$__" = / ] && __=$__/
		;;
	*)
		[ "$__" = / ] && __=/.
		;;
	esac
}

getabspath_() {
	set -f
	IFS=/
	set -- $__

	while :; do
		__='' L=''

		for A; do
			shift

			case "$A" in
			..)
				[ -z "$L" ] && continue
				shift "$#"
				set -- $__ "$@"
				continue 2
				;;
			.|'')
				continue
				;;
			esac

			[ -n "$L" ] && __=$__/$L
			L=$A
		done

		__=$__/$L

		break
	done

	echo "$__"
}

# 4th version - just using awk (some shells doesn't work with the ones above)

getabspath() {
	__=`
		awk -- '
			BEGIN {
				PATH = ARGV[1]

				if (ARGV[1] !~ "^[/]")
					PATH = ARGV[2] "/" PATH

				FS = "/"
				$0 = PATH

				T = 0

				for (F = 1; F <= NF; F++) {
					if ($F == "." || $F == "") {
						continue
					} else if ($F == "..") {
						if (T)
							--T
					} else {
						TOKENS[T++]=$F
					}
				}

				if (T) {
					for (I = 0; I < T; I++)
						ABS = ABS "/" TOKENS[I]
					if (PATH ~ /\/$/)
						ABS = ABS "/"
				} else if (PATH ~ /\/$/) {
					ABS = "/"
				} else {
					ABS = "/."
				}

				print ABS

				exit
			}
		' "$1" "`exec pwd`"
	`
}
getabspath.c - see http://www.linuxquestions.org/questi...ml#post3648275
Posted in Howtos
Views 1921 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 01:39 PM.

Main Menu
Advertisement

Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration