macos - path设定 - 修改path




OS X的Bash脚本绝对路径 (7)

Python解决方案的更多命令行友好变体:

python -c "import os; print(os.path.realpath('$1'))"

我试图获取OS X上当前运行脚本的绝对路径。

我看到许多回复发送给readlink -f $0 。 但是,由于OS X的readlink与BSD相同,它只是不起作用(它适用于GNU的版本)。

有没有开箱即用的解决方案?


基于与评论者的沟通,我同意它非常难以实现与Ubuntu完全相同的实现路径。

但是以下版本,可以处理极端情况下最好的答案不能满足我对macbook的日常需求。 将此代码放入〜/ .bashrc并记住:

  • arg只能是1个文件或dir,没有通配符
  • 目录或文件名中没有空格
  • 至少存在文件或目录的父目录
  • 随意使用。 .. /东西,这些都是安全的
    # 1. if is a dir, try cd and pwd
    # 2. if is a file, try cd its parent and concat dir+file
    realpath() {
     [ "$1" = "" ] && return 1

     dir=`dirname "$1"`
     file=`basename "$1"`

     last=`pwd`

     [ -d "$dir" ] && cd $dir || return 1
     if [ -d "$file" ];
     then
       # case 1
       cd $file && pwd || return 1
     else
       # case 2
       echo `pwd`/$file | sed 's/\/\//\//g'
     fi

     cd $last
    }

啊。 我发现之前的答案有点缺乏原因:特别是,它们没有解决多级符号链接,而且它们非常“Bash-y”。 虽然原始问题明确要求“Bash脚本”,但它也提到了Mac OS X的类BSD,非GNU readlink 。 所以这是尝试一些合理的可移植性(我用bash检查它为'sh'和破折号),解析任意数量的符号链接; 它也应该与路径中的空格一起使用,虽然我不确定该实用程序本身的基本名称是否有空格,所以也许,嗯,避免这种情况?

#!/bin/sh
realpath() {
  OURPWD=$PWD
  cd "$(dirname "$1")"
  LINK=$(readlink "$(basename "$1")")
  while [ "$LINK" ]; do
    cd "$(dirname "$LINK")"
    LINK=$(readlink "$(basename "$1")")
  done
  REALPATH="$PWD/$(basename "$1")"
  cd "$OURPWD"
  echo "$REALPATH"
}
realpath "[email protected]"

希望对某人有用。


因为有其他人指出的realpath

// realpath.c
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char* argv[])
{
  if (argc > 1) {
    for (int argIter = 1; argIter < argc; ++argIter) {
      char *resolved_path_buffer = NULL;
      char *result = realpath(argv[argIter], resolved_path_buffer);

      puts(result);

      if (result != NULL) {
        free(result);
      }
    }
  }

  return 0;
}

Makefile文件:

#Makefile
OBJ = realpath.o

%.o: %.c
      $(CC) -c -o [email protected] $< $(CFLAGS)

realpath: $(OBJ)
      gcc -o [email protected] $^ $(CFLAGS)

然后用make编译并放入一个软链接:
ln -s $(pwd)/realpath /usr/local/bin/realpath


有一个realpath() C函数可以完成这项工作,但我没有在命令行上看到任何可用的东西。 这是一个快速而又脏的替代品:

#!/bin/bash

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

realpath "$0"

如果它以/开头,则逐字打印路径。 如果不是它必须是一个相对路径,所以它预先在前面加上$PWD#./ part从$1的前面剥离./


正如你在上面所看到的那样,我在大约6个月前拍了这张照片。 我完全忘记了它,直到我发现自己再次需要类似的东西。 看到它有多么简陋,我感到非常震惊 ; 我一直在教自己编写相当密集的代码大约一年了,但我常常觉得,当事情处于最糟糕状态时,我根本没有学到任何东西。

我会删除上面的'解决方案',但我真的很喜欢它记录了我在过去几个月里学到了多少。

但我离题了。 我昨晚坐下来彻底解决了这个问题。 评论中的解释应该足够了。 如果你想跟踪我正在继续工作的副本, 你可以按照这个要点。 这可能会满足您的需求。

#!/bin/sh # dash bash ksh # !zsh (issues). G. Nixon, 12/2013. Public domain.

## 'linkread' or 'fullpath' or (you choose) is a little tool to recursively
## dereference symbolic links (ala 'readlink') until the originating file
## is found. This is effectively the same function provided in stdlib.h as
## 'realpath' and on the command line in GNU 'readlink -f'.

## Neither of these tools, however, are particularly accessible on the many
## systems that do not have the GNU implementation of readlink, nor ship
## with a system compiler (not to mention the requisite knowledge of C).

## This script is written with portability and (to the extent possible, speed)
## in mind, hence the use of printf for echo and case statements where they
## can be substituded for test, though I've had to scale back a bit on that.

## It is (to the best of my knowledge) written in standard POSIX shell, and
## has been tested with bash-as-bin-sh, dash, and ksh93. zsh seems to have
## issues with it, though I'm not sure why; so probably best to avoid for now.

## Particularly useful (in fact, the reason I wrote this) is the fact that
## it can be used within a shell script to find the path of the script itself.
## (I am sure the shell knows this already; but most likely for the sake of
## security it is not made readily available. The implementation of "$0"
## specificies that the $0 must be the location of **last** symbolic link in
## a chain, or wherever it resides in the path.) This can be used for some
## ...interesting things, like self-duplicating and self-modifiying scripts.

## Currently supported are three errors: whether the file specified exists
## (ala ENOENT), whether its target exists/is accessible; and the special
## case of when a sybolic link references itself "foo -> foo": a common error
## for beginners, since 'ln' does not produce an error if the order of link
## and target are reversed on the command line. (See POSIX signal ELOOP.)

## It would probably be rather simple to write to use this as a basis for
## a pure shell implementation of the 'symlinks' util included with Linux.

## As an aside, the amount of code below **completely** belies the amount
## effort it took to get this right -- but I guess that's coding for you.

##===-------------------------------------------------------------------===##

for argv; do :; done # Last parameter on command line, for options parsing.

## Error messages. Use functions so that we can sub in when the error occurs.

recurses(){ printf "Self-referential:\n\t$argv ->\n\t$argv\n" ;}
dangling(){ printf "Broken symlink:\n\t$argv ->\n\t"$(readlink "$argv")"\n" ;}
errnoent(){ printf "No such file: "[email protected]"\n" ;} # Borrow a horrible signal name.

# Probably best not to install as 'pathfull', if you can avoid it.

pathfull(){ cd "$(dirname "[email protected]")"; link="$(readlink "$(basename "[email protected]")")"

## 'test and 'ls' report different status for bad symlinks, so we use this.

 if [ ! -e "[email protected]" ]; then if $(ls -d "[email protected]" 2>/dev/null) 2>/dev/null;  then
    errnoent 1>&2; exit 1; elif [ ! -e "[email protected]" -a "$link" = "[email protected]" ];   then
    recurses 1>&2; exit 1; elif [ ! -e "[email protected]" ] && [ ! -z "$link" ]; then
    dangling 1>&2; exit 1; fi
 fi

## Not a link, but there might be one in the path, so 'cd' and 'pwd'.

 if [ -z "$link" ]; then if [ "$(dirname "[email protected]" | cut -c1)" = '/' ]; then
   printf "[email protected]\n"; exit 0; else printf "$(pwd)/$(basename "[email protected]")\n"; fi; exit 0
 fi

## Walk the symlinks back to the origin. Calls itself recursivly as needed.

 while [ "$link" ]; do
   cd "$(dirname "$link")"; newlink="$(readlink "$(basename "$link")")"
   case "$newlink" in
    "$link") dangling 1>&2 && exit 1                                       ;;
         '') printf "$(pwd)/$(basename "$link")\n"; exit 0                 ;;
          *) link="$newlink" && pathfull "$link"                           ;;
   esac
 done
 printf "$(pwd)/$(basename "$newlink")\n"
}

## Demo. Install somewhere deep in the filesystem, then symlink somewhere 
## else, symlink again (maybe with a different name) elsewhere, and link
## back into the directory you started in (or something.) The absolute path
## of the script will always be reported in the usage, along with "$0".

if [ -z "$argv" ]; then scriptname="$(pathfull "$0")"

# Yay ANSI l33t codes! Fancy.
 printf "\n\033[3mfrom/as: \033[4m$0\033[0m\n\n\033[1mUSAGE:\033[0m   "
 printf "\033[4m$scriptname\033[24m [ link | file | dir ]\n\n         "
 printf "Recursive readlink for the authoritative file, symlink after "
 printf "symlink.\n\n\n         \033[4m$scriptname\033[24m\n\n        "
 printf " From within an invocation of a script, locate the script's "
 printf "own file\n         (no matter where it has been linked or "
 printf "from where it is being called).\n\n"

else pathfull "[email protected]"
fi

适用于Mac OS X的realpath

realpath() {
    path=`eval echo "$1"`
    folder=$(dirname "$path")
    echo $(cd "$folder"; pwd)/$(basename "$path"); 
}

相关路径的示例:

realpath "../scripts/test.sh"

主文件夹示例

realpath "~/Test/../Test/scripts/test.sh"






path