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 FILE
或realpath
更好,因为即使文件不存在,它也可以工作。
忘记您的系统上可能安装或不安装的readlink
和realpath
。
在上面的拓展上的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?
它是可移植的,不需要readlink
或readlink
,这通常在给定的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
- 不需要工具(只需
cd
和pwd
) - 适用于目录和文件
- 处理
..
和.
- 处理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 name
或resolved path
)为absolute path
,其中所有符号链接已经被parsing,即已经被链接到的path取代。 realpath
和readlink
命令都查找规范path,但是只有实际path才有获得绝对path的选项,而不会打扰parsing符号链接(以及其他几个选项来获取各种path,绝对或相对于某个目录)。
这需要几个说法:
- 象征性的链接只有在它们应该链接的链接已经被创build的时候才能被解决,这显然并不总是这样。
realpath
和readlink
命令可以解释这个问题。 - path上的目录后来可以成为符号链接,这意味着path不再是
canonical
。 因此,这个概念是时间(或环境)的依赖。 - 即使在理想的情况下,当所有符号链接都可以解决时,仍然可能存在不止一个
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")"
说明:
- 这个脚本获取相对path作为参数
"$1"
- 然后我们得到该path的dirname部分(您可以将dir或文件传递给此脚本):
dirname "$1"
- 然后我们把
cd "$(dirname "$1")
放到这个相对的目录中,并通过运行pwd
shell命令获得它的绝对path - 之后,我们将基本名称追加到绝对path:
$(basename "$1")
- 作为最后一步,我们
echo
它
嘿家伙,我知道这是一个古老的线程,但我只是张贴这个参考谁访问这个像我一样的其他人。 如果我正确地理解了这个问题,我想locate $filename
命令。 它显示提供的文件的绝对path,但只有存在的话。