bash / fish命令打印文件的绝对path

问题:是否有一个简单的sh / bash / zsh / fish / …命令来打印我提供的文件的绝对path?

用例:我在/a/b目录下,我想在命令行上打印文件c的完整path,以便我可以轻松地将它粘贴到另一个程序: /a/b/c 。 简单,但一个小程序来做到这一点可能会节省我5秒左右的时间来处理长path,最后加起来。 所以我很惊讶,我找不到一个标准的工具来做到这一点 – 真的没有?

这是一个示例实现,abspath.py:

 #!/usr/bin/python # Author: Diggory Hardy <diggory.hardy@gmail.com> # Licence: public domain # Purpose: print the absolute path of all input paths import sys import os.path if len(sys.argv)>1: for i in range(1,len(sys.argv)): print os.path.abspath( sys.argv[i] ) sys.exit(0) else: print >> sys.stderr, "Usage: ",sys.argv[0]," PATH." sys.exit(1) 

尝试realpath

 ~ $ realpath .bashrc /home/username/.bashrc 

尝试readlink这将解决符号链接:

 readlink -e /foo/bar/baz 
 #! /bin/sh echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")" 
 $ readlink -m FILE /path/to/FILE 

这比readlink -e FILErealpath更好,因为即使文件不存在,它也可以工作。

忘记您的系统上可能安装或不安装的readlinkrealpath

在上面的拓展上的dogbane的答案它被表示为一个函数:

 #!/bin/bash get_abs_filename() { # $1 : relative filename echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" } 

你可以像这样使用它:

 myabsfile=$(get_abs_filename "../../foo/bar/file.txt") 

如何和为什么它的工作?

该解决scheme利用了Bash内置的pwd命令在调用不带参数的情况下将打印当前目录的绝对path的事实。

为什么我喜欢这个解决scheme?

它是可移植的,不需要readlinkreadlink ,这通常在给定的Linux / Unix发行版的默认安装上不存在。

如果dir不存在呢?

如上所述,如果给定的目录path不存在,该函数将失败并在stderr上打印。 这可能不是你想要的。 您可以扩展function来处理这种情况:

 #!/bin/bash get_abs_filename() { # $1 : relative filename if [ -d "$(dirname "$1")" ]; then echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" fi } 

现在,如果父目录不存在,它将返回一个空string。

你如何处理尾随“..”或“。” 在input?

那么,在这种情况下它确实给出了一个绝对path,但不是最小的path。 它会看起来像:

 /Users/bob/Documents/.. 

如果你想解决'..'你将需要使脚本如:

 get_abs_filename() { # $1 : relative filename filename=$1 parentdir=$(dirname "${filename}") if [ -d "${filename}" ]; then echo "$(cd "${filename}" && pwd)" elif [ -d "${parentdir}" ]; then echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")" fi } 

这个绝对path转换器shell函数的相对path

  • 不需要工具(只需cdpwd
  • 适用于目录和文件
  • 处理...
  • 处理dir或文件名中的空格
  • 需要该文件或目录存在
  • 如果在给定的path上不存在,则不返回任何内容
  • 处理绝对path作为input(实质上传递它们)

码:

 function abspath() { # generate absolute path from relative path # $1 : relative filename # return : absolute path if [ -d "$1" ]; then # dir (cd "$1"; pwd) elif [ -f "$1" ]; then # file if [[ $1 = /* ]]; then echo "$1" elif [[ $1 == */* ]]; then echo "$(cd "${1%/*}"; pwd)/${1##*/}" else echo "$(pwd)/$1" fi fi } 

样品:

 # assume inside /parent/cur abspath file.txt => /parent/cur/file.txt abspath . => /parent/cur abspath .. => /parent abspath ../dir/file.txt => /parent/dir/file.txt abspath ../dir/../dir => /parent/dir # anything cd can handle abspath doesnotexist => # empty result if file/dir does not exist abspath /file.txt => /file.txt # handle absolute path input 

注意:这是基于nolan6000和bsingh的答案,但修复了文件大小写。

我也明白,原来的问题是关于现有的命令行工具。 但是,因为这似乎是在包括希望有最小的依赖关系的shell脚本的stackoverflow的问题,我把这个脚本解决scheme在这里,所以我可以find它以后:)

find命令可能会有所帮助

 find $PWD -name ex* find $PWD -name example.log 

列出名称与模式匹配的当前目录中或下面的所有文件。 如果只能得到一些结果(例如,包含less量文件的树底部的目录),则可以简化它

 find $PWD 

我在Solaris 10上使用它,没有提到其他实用程序。

如果你没有readlink或realpath实用程序,你可以使用下面的函数在bash和zsh中工作(不知道其他的)。

 abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; } 

这也适用于不存在的文件(如python函数os.path.abspath )。

不幸的是abspath ./../somefile没有摆脱点。

这是一个zsh-onlyfunction,我喜欢它的紧凑性。 它使用“A”扩展修饰符 – 请参阅zshexpn(1)。

 realpath() { for f in "$@"; do echo ${f}(:A); done } 

通常没有文件 absolute path (这个语句意味着一般可能有多于一个,因此使用定冠词是不合适的)。 absolute path是从根“/”开始的任何path,并且独立于工作目录指定一个没有歧义的文件(参见例如维基百科 )。

relative path是从另一个目录开始解释的path。 它可能是工作目录,如果它是由应用程序操作的relative path (尽pipe不一定)。 当它在一个目录中的符号链接中时,通常打算与该目录相关(尽pipe用户可能有其他用途)。

因此绝对path只是相对于根目录的path。

path(绝对或相对)可以包含或不包含符号链接。 如果没有,连接结构的变化也是有些不可避免的,但这不是必需的,甚至是不可取的。 有些人称canonical path (或canonical file nameresolved path )为absolute path ,其中所有符号链接已经被parsing,即已经被链接到的path取代。 realpathreadlink命令都查找规范path,但是只有实际path才有获得绝对path的选项,而不会打扰parsing符号链接(以及其他几个选项来获取各种path,绝对或相对于某个目录)。

这需要几个说法:

  1. 象征性的链接只有在它们应该链接的链接已经被创build的时候才能被解决,这显然并不总是这样。 realpathreadlink命令可以解释这个问题。
  2. path上的目录后来可以成为符号链接,这意味着path不再是canonical 。 因此,这个概念是时间(或环境)的依赖。
  3. 即使在理想的情况下,当所有符号链接都可以解决时,仍然可能存在不止一个canonical path的文件canonical path ,原因有二:
    • 包含该文件的分区可能已同时安装( ro )在多个安装点上。
    • 有可能是硬链接到文件,这意味着文件存在于几个不同的目录。

因此,即使canonical path限制性更严格,也可能有几条规范的文件path。 这也意味着canonical性有些不足,因为它通常意味着唯一性的概念。

这就在Bash的另一个类似问题的答案中扩展了关于该主题的简要讨论:检索给定相对的绝对path

我的结论是realpath的devise更好,比readlink更灵活。 只有readlink没有被realpath覆盖的用途是调用没有选项返回符号链接的值。

我将下面的脚本放在我的系统上,我把它叫做bash别名,当我想快速获取当前目录中文件的完整path时:

 #!/bin/bash /usr/bin/find "$PWD" -maxdepth 1 -mindepth 1 -name "$1" 

我不知道为什么,但是,当在脚本“$ PWD”调用的OS X上扩展到绝对path。 在命令行中调用find命令时,不会。 但它做我想要的…享受。

对于目录dirname获取../并返回./

nolan6000的function可以修改,以解决:

 get_abs_filename() { # $1 : relative filename if [ -d "${1%/*}" ]; then echo "$(cd ${1%/*}; pwd)/${1##*/}" fi } 
 #! /bin/bash file="$@" realpath "$file" 2>/dev/null || eval realpath $(echo $file | sed 's/ /\\ /g') 

这弥补了realpath的缺点,将其存储在shell脚本fullpath 。 你现在可以打电话给:

 $ cd && touch a\ a && rm A 2>/dev/null $ fullpath "aa" /home/user/aa $ fullpath ~/a\ a /home/user/aa $ fullpath A A: No such file or directory. 

这不是对这个问题的回答,但对于那些做脚本的人来说:

 echo `cd "$1" 2>/dev/null&&pwd||(cd "$(dirname "$1")";pwd|sed "s|/*\$|/${1##*/}|")` 

它正确处理/ .. ./等。 我似乎也在OSX上工作

Ruby中获得绝对path的另一种方法是:

realpath() {ruby -e "require 'Pathname'; puts Pathname.new('$1').realpath.to_s";}

无参数(当前文件夹)和相对和绝对文件或文件夹path作为agument工作。

与描述的dogbane 答案是什么来的:

 #! /bin/sh echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")" 

说明:

  1. 这个脚本获取相对path作为参数"$1"
  2. 然后我们得到该path的dirname部分(您可以将dir或文件传递给此脚本): dirname "$1"
  3. 然后我们把cd "$(dirname "$1")放到这个相对的目录中,并通过运行pwd shell命令获得它的绝对path
  4. 之后,我们将基本名称追加到绝对path: $(basename "$1")
  5. 作为最后一步,我们echo

嘿家伙,我知道这是一个古老的线程,但我只是张贴这个参考谁访问这个像我一样的其他人。 如果我正确地理解了这个问题,我想locate $filename命令。 它显示提供的文件的绝对path,但只有存在的话。