bash - path追加 - 添加path




bash脚本获得完整路径的可靠方法? (16)

这个问题在这里已经有了答案:

我有一个bash脚本,需要知道它的完整路径。 我试图找到一个广泛兼容的方式来做到这一点,而不会结束相对或时髦的路径。 我只需要支持bash,而不是sh,csh等。

到目前为止,我发现了什么:

  1. 从内部获取Bash脚本的源目录 ”地址的公认答案通过dirname $0获取脚本的路径,这很好,但是可能会返回一个相对路径(如. ),如果你想要,这是一个问题更改脚本中的目录并让路径仍指向脚本的目录。 尽管如此, dirname仍然是谜题的一部分。

  2. 被接受的答案是“ OSX的Bash脚本绝对路径(特定于OS X,但答案无论如何)都给出了一个函数,用于测试$0是否相对,如果是,则会预先给$PWD 。 但是结果仍然可能有相对位(尽管总体上它是绝对的) - 例如,如果脚本在目录/usr/bin并且在/usr并且您键入bin/../bin/t要运行它(是的,这很复杂),最终将以/usr/bin/../bin作为脚本的目录路径。 哪些工作 ,但...

  3. 此页面上readlink解决方案如下所示:

    # Absolute path to this script. /home/user/bin/foo.sh
    SCRIPT=$(readlink -f $0)
    # Absolute path this script is in. /home/user/bin
    SCRIPTPATH=`dirname $SCRIPT`
    

    但是readlink不是POSIX,显然这个解决方案依赖于GNU的readlink ,因为BSD不会出于某种原因工作(我没有访问类似BSD的系统来检查)。

所以,采取不同的方式,但他们都有自己的警告。

什么会更好? “更好”的意思是:

  • 给我绝对的道路。
  • 即使以错综复杂的方式调用时也会发出时髦的位(参见上面#2的评论)。 (例如,至少适度规范化路径。)
  • 仅依赖于bash-isms或几乎可以肯定在* nix系统(GNU / Linux,BSD和类似BSD的系统,如OS X等)最流行的版本的东西。
  • 如果可能的话,避免调用外部程序(例如,更喜欢bash内置插件)。
  • 更新 ,谢谢你的提醒, wich )无需解析符号链接(事实上,我宁愿让它们独立,但这不是必需的)。

获取shell脚本的绝对路径

在readlink中不使用-f选项,因此应该在bsd / mac-osx中工作

支持

  • 源./script(由.点运算符调用时)
  • 绝对路径/路径/到/脚本
  • 相对路径,如./script
  • /path/dir1/../dir2/dir3/../script
  • 从符号链接调用时
  • 当符号链接嵌套时,例如foo->dir1/dir2/bar bar->./../doe doe->script
  • 调用者更改脚本名称时

我正在寻找这种代码无效的角落案例 。 请告诉我。

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
while([ -h "${SCRIPT_PATH}" ]); do
    cd "`dirname "${SCRIPT_PATH}"`"
    SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
done
cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
SCRIPT_PATH="`pwd`";
popd  > /dev/null
echo "srcipt=[${SCRIPT_PATH}]"
echo "pwd   =[`pwd`]"

已知的问题

脚本必须放在磁盘上 ,让它通过网络。 如果您尝试从PIPE运行此脚本,它将无法工作

wget -o /dev/null -O - http://host.domain/dir/script.sh |bash

从技术上讲,它是不确定的。
实际上,没有一种合理的方法来检测这一点。 (协同进程无法访问父级的环境)


一个班轮

`dirname $(realpath $0)`

也许对以下问题的接受答案可能有帮助。

如何在Mac上获得GNU的readlink -f的行为?

鉴于你只是想要将从$ PWD和$ 0连接得到的名称进行规范化(假设$ 0不是绝对开始的)。只需沿着abs_dir=${abs_dir//\/.\//\/} line这一行使用一系列正则表达式替换abs_dir=${abs_dir//\/.\//\/}等等。

是的,我知道它看起来很可怕,但它会起作用,并且是纯粹的bash。


仅仅为了它而已,我已经对脚本进行了一些黑客攻击,纯粹以纯文本方式进行,纯粹是以bash的方式进行。 我希望我抓住了所有的边缘情况。 请注意,我在其他答案中提到的${var//pat/repl}不起作用,因为您无法仅替换最短匹配项,这是将/foo/../替换为例如/*/../将采取一切之前,而不是一个单一的条目。 而且由于这些模式并不是真正的正则表达式,所以我不知道如何才能使其工作。 所以这里是我提出的很好的复杂解决方案,享受。 ;)

顺便说一句,让我知道如果你发现任何未处理的边缘情况。

#!/bin/bash

canonicalize_path() {
  local path="$1"
  OIFS="$IFS"
  IFS=$'/'
  read -a parts < <(echo "$path")
  IFS="$OIFS"

  local i=${#parts[@]}
  local j=0
  local back=0
  local -a rev_canon
  while (($i > 0)); do
    ((i--))
    case "${parts[$i]}" in
      ""|.) ;;
      ..) ((back++));;
      *) if (($back > 0)); then
           ((back--))
         else
           rev_canon[j]="${parts[$i]}"
           ((j++))
         fi;;
    esac
  done
  while (($j > 0)); do
    ((j--))
    echo -n "/${rev_canon[$j]}"
  done
  echo
}

canonicalize_path "/.././..////../foo/./bar//foo/bar/.././bar/../foo/bar/./../..//../foo///bar/"

回答这个问题很晚,但我用:

SCRIPT=$( readlink -m $( type -p $0 ))      # Full path to script
BASE_DIR=`dirname ${SCRIPT}`                # Directory script is run in
NAME=`basename ${SCRIPT}`                   # Actual name of script even if linked

如果我们使用Bash,我相信这是最方便的方式,因为它不需要调用任何外部命令:

THIS_PATH="${BASH_SOURCE[0]}";
THIS_DIR=$(dirname $THIS_PATH)

怎么样使用:

SCRIPT_PATH=$(dirname `which $0`)

打印出标准输出可执行文件的完整路径,当在shell提示符下输入传入的参数时(这是$ 0包含的内容)

dirname从文件名dirname非目录后缀

因此,无论路径是否被指定,结果都是脚本的完整路径。


您可以尝试定义以下变量:

CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"

或者你可以在bash中尝试下面的函数:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

该函数需要1个参数。 如果参数已经有绝对路径,按原样打印它,否则打​​印$PWD变量+文件名参数(不带./前缀)。

有关:


我们已将自己的产品realpath-lib放在GitHub上,免费和无阻碍地使用社区。

无耻的插件,但与这个Bash库你可以:

get_realpath <absolute|relative|symlink|local file>

这个功能是库的核心:

function get_realpath() {

if [[ -f "$1" ]]
then 
    # file *must* exist
    if cd "$(echo "${1%/*}")" &>/dev/null
    then 
        # file *may* not be local
        # exception is ./file.ext
        # try 'cd .; cd -;' *works!*
        local tmppwd="$PWD"
        cd - &>/dev/null
    else 
        # file *must* be local
        local tmppwd="$PWD"
    fi
else 
    # file *cannot* exist
    return 1 # failure
fi

# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success

}

它不需要任何外部依赖,只需Bash 4+。 还包含函数get_dirnameget_filenameget_stemname validate_path validate_realpath 。 它是免费的,干净的,简单的和有据可查的,所以它也可以用于学习的目的,毫无疑问可以改进。 尝试跨平台。

更新:经过一些审查和测试,我们已经取代了上述功能,取得了相同的结果(不使用dirname,只使用纯Bash),但效率更高:

function get_realpath() {

    [[ ! -f "$1" ]] && return 1 # failure : file does not exist.
    [[ -n "$no_symlinks" ]] && local pwdp='pwd -P' || local pwdp='pwd' # do symlinks.
    echo "$( cd "$( echo "${1%/*}" )" 2>/dev/null; $pwdp )"/"${1##*/}" # echo result.
    return 0 # success

}

这还包括一个环境设置no_symlinks ,它提供了解析符号链接到物理系统的能力。 默认情况下,它保持符号链接不变。


我发现在bash中获得完整规范路径的最简单方法是使用cdpwd

ABSOLUTE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"

使用${BASH_SOURCE[0]}而不是$0会产生相同的行为,无论脚本是作为<name>还是source <name>调用的


我很惊讶realpath命令在这里没有提到。 我的理解是,它被广泛地移植/移植。

你的初始解决方案变成

SCRIPT=`realpath $0`
SCRIPTPATH=`dirname $SCRIPT`

并且根据您的偏好留下未解决的符号链接:

SCRIPT=`realpath -s $0`
SCRIPTPATH=`dirname $SCRIPT`

接受的解决方案对我来说不方便(源于我)不是“源代码”:
如果你从“ source ../../yourScript ”中调用它, $0就是“ bash ”!

下面的函数(对于bash> = 3.0)给了我正确的路径,但是可以调用脚本(直接或通过source ,具有绝对路径或相对路径):
(通过“正确的路径”,我指的是被调用的脚本完全绝对路径 ,即使从另一路径直接调用或以“ source ”调用)

#!/bin/bash
echo $0 executed

function bashscriptpath() {
  local _sp=$1
  local ascript="$0"
  local asp="$(dirname $0)"
  #echo "b1 asp '$asp', b1 ascript '$ascript'"
  if [[ "$asp" == "." && "$ascript" != "bash" && "$ascript" != "./.bashrc" ]] ; then asp="${BASH_SOURCE[0]%/*}"
  elif [[ "$asp" == "." && "$ascript" == "./.bashrc" ]] ; then asp=$(pwd)
  else
    if [[ "$ascript" == "bash" ]] ; then
      ascript=${BASH_SOURCE[0]}
      asp="$(dirname $ascript)"
    fi  
    #echo "b2 asp '$asp', b2 ascript '$ascript'"
    if [[ "${ascript#/}" != "$ascript" ]]; then asp=$asp ;
    elif [[ "${ascript#../}" != "$ascript" ]]; then
      asp=$(pwd)
      while [[ "${ascript#../}" != "$ascript" ]]; do
        asp=${asp%/*}
        ascript=${ascript#../}
      done
    elif [[ "${ascript#*/}" != "$ascript" ]];  then
      if [[ "$asp" == "." ]] ; then asp=$(pwd) ; else asp="$(pwd)/${asp}"; fi
    fi  
  fi  
  eval $_sp="'$asp'"
}

bashscriptpath H
export H=${H}

关键是要检测“ source ”情况并使用${BASH_SOURCE[0]}取回实际脚本。


更简单地说,这对我来说很有用:

MY_DIR=`dirname $0`
source $MY_DIR/_inc_db.sh

由于我的Linux系统上默认情况下没有安装实际路径,因此以下内容适用于我:

SCRIPT="$(readlink --canonicalize-existing "$0")"
SCRIPTPATH="$(dirname "$SCRIPT")"

$SCRIPT将包含$SCRIPT的真实文件路径, $SCRIPTPATH包含脚本的目录的真实路径。

在使用之前阅读这个答案的评论。


简单地说: BASEDIR=$(readlink -f $0 | xargs dirname)

没有花哨的运营商

HIH。


还有另一种方法来做到这一点:

shopt -s extglob

selfpath=$0
selfdir=${selfpath%%+([!/])}

while [[ -L "$selfpath" ]];do
  selfpath=$(readlink "$selfpath")
  if [[ ! "$selfpath" =~ ^/ ]];then
    selfpath=${selfdir}${selfpath}
  fi
  selfdir=${selfpath%%+([!/])}
done

echo $selfpath $selfdir




path