Bash script absolute path with OS X
我正在尝试获取OS X上当前运行脚本的绝对路径。
我看到很多回复都是针对
有现成的解决方案吗?
这三个简单步骤将解决这一问题和许多其他OS X问题:
(3)可改为仅
有一个
1 2 3 4 5 6 7 | #!/bin/bash realpath() { [[ $1 = /* ]] && echo"$1" || echo"$PWD/${1#./}" } realpath"$0" |
如果路径以
呃。我发现之前的答案有点欠缺,原因有几个:特别是,它们不能解析多个层次的符号链接,而且它们是非常"bash-y"。虽然最初的问题确实明确要求使用"bash脚本",但它也提到了mac os x类似于BSD的非GNU
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/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"$@" |
希望这对某人有用。
python解决方案的一个更友好的命令行变体:
1 | python -c"import os; print(os.path.realpath('$1'))" |
因为有一条真正的道路,正如其他人所指出的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // 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:
1 2 3 4 5 6 7 8 | #Makefile OBJ = realpath.o %.o: %.c $(CC) -c -o $@ $< $(CFLAGS) realpath: $(OBJ) gcc -o $@ $^ $(CFLAGS) |
然后用
使用python获取:
1 2 3 4 5 | #!/usr/bin/env python import os import sys print(os.path.realpath(sys.argv[1])) |
我正在寻找一个可用于系统配置脚本的解决方案,即在安装自制之前运行。由于缺乏适当的解决方案,我只需将任务卸载到跨平台语言,例如Perl:
1 | script_abspath=$(perl -e 'use Cwd"abs_path"; print abs_path(@ARGV[0])' --"$0") |
通常我们真正想要的是包含目录:
1 | here=$(perl -e 'use File::Basename; use Cwd"abs_path"; print dirname(abs_path(@ARGV[0]));' --"$0") |
正如你在上面看到的,大约6个月前我拍了一张照片。我完全忘了它,直到我发现自己又需要类似的东西。我是完全震惊地看到它是多么的初级;我一直在教书我自己已经花了大约一年的时间集中编写代码了,但我经常觉得也许在最坏的时候我什么都没学到。
我会删除上面的"解决方案",但我真的希望它是在过去的几个月里我真正学到了多少。
但我离题了。我昨天晚上坐下来,把一切都解决了。解释这些评论应该足够了。如果你想追踪副本,我会继续为了继续工作,你可以遵循这个要点。这可能是你需要的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | #!/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: \t$argv -> \t$argv " ;} dangling(){ printf"Broken symlink: \t$argv -> \t"$(readlink"$argv")" " ;} errnoent(){ printf"No such file:"$@" " ;} # Borrow a horrible signal name. # Probably best not to install as 'pathfull', if you can avoid it. pathfull(){ cd"$(dirname"$@")"; link="$(readlink"$(basename"$@")")" ## 'test and 'ls' report different status for bad symlinks, so we use this. if [ ! -e"$@" ]; then if $(ls -d"$@" 2>/dev/null) 2>/dev/null; then errnoent 1>&2; exit 1; elif [ ! -e"$@" -a"$link" ="$@" ]; then recurses 1>&2; exit 1; elif [ ! -e"$@" ] && [ ! -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"$@" | cut -c1)" = '/' ]; then printf"$@ "; exit 0; else printf"$(pwd)/$(basename"$@") "; 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") "; exit 0 ;; *) link="$newlink" && pathfull"$link" ;; esac done printf"$(pwd)/$(basename"$newlink") " } ## 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" \033[3mfrom/as: \033[4m$0\033[0m \033[1mUSAGE:\033[0m " printf"\033[4m$scriptname\033[24m [ link | file | dir ] " printf"Recursive readlink for the authoritative file, symlink after" printf"symlink. \033[4m$scriptname\033[24m " printf" From within an invocation of a script, locate the script's" printf"own file (no matter where it has been linked or" printf"from where it is being called). " else pathfull"$@" fi |
Mac OS X的realpath
1 2 3 4 5 | realpath() { path=`eval echo"$1"` folder=$(dirname"$path") echo $(cd"$folder"; pwd)/$(basename"$path"); } |
具有相关路径的示例:
1 | realpath"../scripts/test.sh" |
主文件夹示例
1 | realpath"~/Test/../Test/scripts/test.sh" |
基于与评论者的沟通,我同意这是非常困难的,没有繁琐的方式来实现一个真正的路径行为完全相同的Ubuntu。
但下面的版本,可以处理角箱的最佳答案,不能满足我对MacBook的日常需求。将此代码放入~/.bashrc并记住:
- arg只能是1个文件或目录,没有通配符
- 目录或文件名中没有空格
- 至少存在文件或目录的父目录
- 请随意使用。…/东西,这些是安全的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # 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 } |