BASIS  r3148
path.sh
Go to the documentation of this file.
00001 ##############################################################################
00002 # @file  os/path.sh
00003 # @brief Path manipulation functions.
00004 #
00005 # Copyright (c) 2011, 2012 University of Pennsylvania. All rights reserved.<br />
00006 # See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.
00007 #
00008 # Contact: SBIA Group <sbia-software at uphs.upenn.edu>
00009 ##############################################################################
00010 
00011 [ "${_BASIS_OS_PATH_INCLUDED}" == 'true' ] || {
00012 _BASIS_OS_PATH_INCLUDED='true'
00013 
00014 
00015 . "`cd -P -- \`dirname -- "${BASH_SOURCE}"\` && pwd`/../config.sh" || exit 1
00016 
00017 
00018 ## @addtogroup BasisBashUtilities
00019 #  @{
00020 
00021 
00022 # ----------------------------------------------------------------------------
00023 ## @brief Clean path, i.e., remove occurences of "./", duplicate slashes,...
00024 #
00025 # This function removes single periods (.) enclosed by slashes or backslashes,
00026 # duplicate slashes (/) or backslashes (\), and further tries to reduce the
00027 # number of parent directory references.
00028 #
00029 # For example, "../bla//.//.\bla\\\\\bla/../.." is convert to "../bla".
00030 #
00031 # @param [in] path Path.
00032 #
00033 # @return Cleaned path.
00034 normpath()
00035 {
00036     local _basis_cp_path="$1"
00037     # GNU bash, version 3.00.15(1)-release (x86_64-redhat-linux-gnu)
00038     # turns the array into a single string value if local is used
00039     if [ ${BASH_VERSION_MAJOR} -gt 3 ] || [ ${BASH_VERSION_MAJOR} -eq 3 -a ${BASH_VERSION_MINOR} -gt 0 ]; then
00040         local _basis_cp_dirs=()
00041     else
00042         _basis_cp_dirs=()
00043     fi
00044     # split path into parts, discarding redundant slashes
00045     while [ -n "${_basis_cp_path}" ]; do
00046         if [ ${#_basis_cp_dirs[@]} -eq 0 ]; then
00047             _basis_cp_dirs=("`basename -- "${_basis_cp_path}"`")
00048         else
00049             _basis_cp_dirs=("`basename -- "${_basis_cp_path}"`" "${_basis_cp_dirs[@]}")
00050         fi
00051         _basis_cp_path="`dirname -- "${_basis_cp_path}"`"
00052         if [ "${_basis_cp_path}" == '/' ]; then
00053             _basis_cp_path=''
00054         fi
00055     done
00056     # build up path again from the beginning,
00057     # discarding dots ('.') and stepping one level up for each '..' 
00058     local _basis_cp_i=0
00059     while [ ${_basis_cp_i} -lt ${#_basis_cp_dirs[@]} ]; do
00060         if [ "${_basis_cp_dirs[${_basis_cp_i}]}" != '.' ]; then
00061             if [ "${_basis_cp_dirs[${_basis_cp_i}]}" == '..' ]; then
00062                 _basis_cp_path=`dirname -- "${_basis_cp_path}"`
00063             else
00064                 _basis_cp_path="${_basis_cp_path}/${_basis_cp_dirs[${_basis_cp_i}]}"
00065             fi
00066         fi
00067         let _basis_cp_i++
00068     done
00069     # return
00070     echo -n "${_basis_cp_path}"
00071 }
00072 
00073 # ----------------------------------------------------------------------------
00074 ## @brief Get absolute path given a relative path.
00075 #
00076 # This function converts a relative path to an absolute path. If the given
00077 # path is already absolute, this path is passed through unchanged.
00078 #
00079 # @param [in] path Absolute or relative path.
00080 #
00081 # @return Absolute path.
00082 abspath()
00083 {
00084     local _basis_tap_base="$1"
00085     local _basis_tap_path="$2"
00086     if [ "${_basis_tap_base:0:1}" != '/' ]; then
00087         _basis_tap_base="`pwd`/${_basis_tap_base}"
00088     fi
00089     if [ "${_basis_tap_path:0:1}" != '/' ]; then
00090         _basis_tap_path="${_basis_tap_base}/${_basis_tap_path}"
00091     fi
00092     normpath "${_basis_tap_path}"
00093 }
00094 
00095 # ----------------------------------------------------------------------------
00096 ## @brief Get canonical file path.
00097 #
00098 # This function resolves symbolic links and returns a cleaned path.
00099 #
00100 # @param [in] path Path.
00101 #
00102 # @return Canonical file path without duplicate slashes, ".", "..",
00103 #         and symbolic links.
00104 realpath()
00105 {
00106     # make path absolute and resolve '..' references
00107     local _basis_grp_path=`abspath "$1"`
00108     if ! [ -e "${_basis_grp_path}" ]; then echo -n "${_basis_grp_path}"; return; fi
00109     # resolve symbolic links within path
00110     _basis_grp_path=`cd -P -- $(dirname -- "${_basis_grp_path}") && pwd -P`/`basename -- "${_basis_grp_path}"`
00111     # if path itself is a symbolic link, follow it
00112     local _basis_grp_i=0
00113     local _basis_grp_cur="${_basis_grp_path}"
00114     while [ -h "${_basis_grp_cur}" ] && [ ${_basis_grp_i} -lt 100 ]; do
00115         _basis_grp_dir=`dirname -- "${_basis_grp_cur}"`
00116         _basis_grp_cur=`readlink -- "${_basis_grp_cur}"`
00117         _basis_grp_cur=`cd "${_basis_grp_dir}" && cd $(dirname -- "${_basis_grp_cur}") && pwd`/`basename -- "${_basis_grp_cur}"`
00118         let _basis_grp_i++
00119     done
00120     # If symbolic link could entirely be resolved in less than 100 iterations,
00121     # return the obtained canonical file path. Otherwise, return the original
00122     # link which could not be resolved due to some probable cycle.
00123     if [ ${_basis_grp_i} -lt 100 ]; then _basis_grp_path="${_basis_grp_cur}"; fi
00124     # return
00125     echo -n "${_basis_grp_path}"
00126 }
00127 
00128 
00129 ## @}
00130 # end of Doxygen group
00131 
00132 
00133 } # _BASIS_PATH_INCLUDED