如何通过Shell(BASH/ZSH/SH)获取文件的绝对路径?
问题:是否有一个简单的 sh/bash/zsh/fish/... 命令来打印我提供的任何文件的绝对路径?
用例:我位于目录 /a/b
中,我想在命令行上打印文件 c
的完整路径,以便我可以轻松粘贴它进入另一个程序:/a/b/c
。在处理长路径时,简单但一个小程序可以为我节省 5 秒左右的时间,最终加起来。因此,令我惊讶的是,我找不到一个标准实用程序来执行此操作 - 真的没有吗?
这是一个示例实现,abspath.py:
#!/usr/bin/python
# Author: Diggory Hardy <[email protected]>
# 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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(24)
使用
realpath
Use
realpath
尝试
readlink
这将解析符号链接:Try
readlink
which will resolve symbolic links:忘记您的系统上可能安装或未安装的
readlink
和realpath
。扩展上面的dogbane的答案,它被表示为一个函数:
然后你可以像这样使用它:
它如何以及为什么工作?
该解决方案利用了这样一个事实:Bash 内置
pwd
命令在不带参数调用时将打印当前目录的绝对路径。为什么我喜欢这个解决方案?
它是可移植的,并且不需要
readlink
或realpath
,而给定 Linux/Unix 发行版的默认安装中通常不存在这些。如果 dir 不存在怎么办?
如上所述,如果给定的目录路径不存在,该函数将失败并在 stderr 上打印。这可能不是您想要的。您可以扩展该函数来处理这种情况:
现在,如果父目录不存在,它将返回一个空字符串。
如何处理尾随的“..”或“.”在输入?
好吧,在这种情况下它确实给出了绝对路径,但不是最小路径。它看起来像:
如果你想解析“..”,你需要使脚本如下:
Forget about
readlink
andrealpath
which may or may not be installed on your system.Expanding on dogbane's answer above here it is expressed as a function:
you can then use it like this:
How and why does it work?
The solution exploits the fact that the Bash built-in
pwd
command will print the absolute path of the current directory when invoked without arguments.Why do I like this solution ?
It is portable and doesn't require neither
readlink
orrealpath
which often does not exist on a default install of a given Linux/Unix distro.What if dir doesn't exist?
As given above the function will fail and print on stderr if the directory path given does not exist. This may not be what you want. You can expand the function to handle that situation:
Now it will return an empty string if one the parent dirs do not exist.
How do you handle trailing '..' or '.' in input ?
Well, it does give an absolute path in that case, but not a minimal one. It will look like:
If you want to resolve the '..' you will need to make the script like:
这比 readlink -e FILE 或 realpath 更好,因为即使文件不存在它也能工作。
This is better than
readlink -e FILE
orrealpath
, because it works even if the file doesn't exist.这种相对路径到绝对路径转换器shell函数
cd
和pwd
),..
和.
代码:
示例:
< em>注意:这是基于 nolan6000 和 bsingh,但修复了文件大小写。
我也了解最初的问题是关于现有的命令行实用程序。但由于这似乎是 stackoverflow 上的问题,其中包括希望具有最小依赖关系的 shell 脚本,因此我将此脚本解决方案放在这里,以便稍后可以找到它:)
This relative path to absolute path converter shell function
cd
andpwd
)..
and.
Code:
Sample:
Note: This is based on the answers from nolan6000 and bsingh, but fixes the file case.
I also understand that the original question was about an existing command line utility. But since this seems to be THE question on stackoverflow for that including shell scripts that want to have minimal dependencies, I put this script solution here, so I can find it later :)
find
命令可能会帮助列出当前目录中或当前目录下名称与模式匹配的所有文件。如果您只得到几个结果(例如,靠近树底部的目录,包含几个文件),您可以简化它,只是
我在 Solaris 10 上使用它,它没有提到的其他实用程序。
The
find
command may helpLists all the files in or below the current directory with names matching the pattern. You can simplify it if you will only get a few results (e.g. directory near bottom of tree containing few files), just
I use this on Solaris 10, which doesn't have the other utilities mentioned.
这是一个仅限 zsh 的函数,我喜欢它的紧凑性。它使用“A”扩展修饰符 - 请参阅 zshexpn(1)。
Here's a zsh-only function that I like for its compactness. It uses the ‘A’ expansion modifier — see zshexpn(1).
如果您没有 readlink 或 realpath 实用程序,则可以使用以下在 bash 和 zsh 中工作的函数(不确定其余的)。
这也适用于不存在的文件(Python 函数 os.path.abspath 也是如此)。
不幸的是
abspath ./../somefile
并没有去掉这些点。If you don't have readlink or realpath utilities than you can use following function which works in bash and zsh (not sure about the rest).
This also works for nonexistent files (as does the python function
os.path.abspath
).Unfortunately
abspath ./../somefile
doesn't get rid of the dots.通常不存在文件的绝对路径(这一说法意味着一般情况下可能有多个,因此使用定冠词 > 是不合适的)。
绝对路径
是从根“/”开始的任何路径,并指定一个独立于工作目录而没有歧义的文件。(参见示例维基百科)。相对路径是从另一个目录开始解释的路径。如果它是由应用程序操作的
相对路径
,则它可能是工作目录(虽然不一定)。当它位于目录中的符号链接中时,它通常是相对于该目录的(尽管用户可能有其他用途)。
因此,绝对路径只是相对于根目录的路径。
路径(绝对或相对)可能包含也可能不包含符号链接。如果不这样做,则它在某种程度上也不受链接结构变化的影响,但这不一定是必需的,甚至不是所希望的。有些人将
规范路径
(或规范文件名
或解析路径
)称为绝对路径
,其中所有符号链接已解决,即已被替换为它们链接到的路径。命令realpath
和readlink
都查找规范路径,但只有realpath
可以选择获取绝对路径,而无需费心解析符号链接(以及其他几个选项来获取各种类型的路径,绝对路径或相对于某个目录的路径)。这需要注意几点:
链接已创建,显然情况并非总是如此。命令
realpath
和readlink
有选项来解决这个问题。规范
。因此,这个概念是依赖于时间(或环境)的。一个文件可能仍然有多个
规范路径
,对于两个原因:
ro
) 到多个挂载点上。因此,即使对规范路径的定义更加严格,一个文件也可能有多个规范路径。这也意味着限定符
canonical
有些不充分,因为它通常意味着唯一性的概念。这扩展了在另一个类似问题的答案中对该主题的简短讨论: Bash:检索给定相对路径的绝对路径
我的结论是,
realpath
比readlink
设计得更好,也更灵活。realpath
未涵盖的readlink
的唯一用途是不带选项返回符号链接值的调用。There is generally no such thing as the
absolute path
to a file (this statement means that there may be more than one in general, hence the use of the definite article the is not appropriate). Anabsolute path
is any path that start from the root "/" and designates a file without ambiguity independently of the working directory.(see for example wikipedia).A
relative path
is a path that is to be interpreted starting from another directory. It may be the working directory if it is arelative path
being manipulated by an application(though not necessarily). When it is in a symbolic link in a directory, it is generally intended to be relative to that directory (though the user may have other uses in mind).
Hence an absolute path is just a path relative to the root directory.
A path (absolute or relative) may or may not contain symbolic links. If it does not, it is also somewhat impervious to changes in the linking structure, but this is not necessarily required or even desirable. Some people call
canonical path
( orcanonical file name
orresolved path
) anabsolute path
in which all symbolic links have been resolved, i.e. have been replaced by a path to whetever they link to. The commandsrealpath
andreadlink
both look for a canonical path, but onlyrealpath
has an option for getting an absolute path without bothering to resolve symbolic links (along with several other options to get various kind of paths, absolute or relative to some directory).This calls for several remarks:
link to is already created, which is obviously not always the case. The commands
realpath
andreadlink
have options to account for that.canonical
. Hence the concept is time (or environment) dependent.there may still be more than one
canonical path
to a file, for tworeasons:
ro
) on several mount points.Hence, even with the much more restrictive definition of
canonical path
, there may be several canonical paths to a file. This also means that the qualifiercanonical
is somewhat inadequate since it usually implies a notion of uniqueness.This expands a brief discussion of the topic in an answer to another similar question at Bash: retrieve absolute path given relative
My conclusion is that
realpath
is better designed and much more flexible thanreadlink
.The only use of
readlink
that is not covered byrealpath
is the call without option returning the value of a symbolic link.如果您只想使用内置程序,最简单的方法可能是:
只需额外键入两个单词,这将适用于所有 UNIX 系统以及 OSX。
The simplest if you want to use only builtins is probably:
Only an extra two words to type, and this will work on all unix systems, as well as OSX.
dogbane
answer 并描述了即将发生的情况:说明:
"$1"
dirname "$1"
cd "$(dirname "$1")
进入这个相对目录,并通过运行pwd
shell 命令获取它的绝对路径$(basename "$1")
echo
它The
dogbane
answer with the description what is coming on:Explanation:
"$1"
dirname "$1"
cd "$(dirname "$1")
into this relative dir and get absolute path for it by runningpwd
shell command$(basename "$1")
echo
it使用 Homebrew
realpath
回答是最好的答案,但如果您没有安装它,则必须首先运行brew install coreutils
它将安装 coreutils 具有许多很棒的功能。编写自定义函数并导出它的工作量太大,而且对于这样的事情存在出错的风险,这里有两行:Answer with Homebrew
realpath
is the best answer, but if you don't have it installed, you must first runbrew install coreutils
which will install coreutils with lots of awesome functions. Writing a custom function and exporting it is too much work and risk for error for something like this, here are two lines:在某些情况下,此问题的最佳答案可能会产生误导。想象一下,您要查找其绝对路径的文件位于
$PATH
变量中:根据上述内容,我可以得出结论:
realpath -e
和readlink -e
可用于查找我们期望当前目录中存在的文件的绝对路径,结果不受$PATH<的影响/code> 变量
。唯一的区别是
realpath
输出到 stderr,但如果找不到文件,两者都会返回错误代码:现在,如果您想要
中存在的文件的绝对路径 a $PATH
,以下命令是合适的,与当前目录中是否存在同名文件无关。还有,如果丢失,则回退到
$PATH
,例如:The top answers in this question may be misleading in some cases. Imagine that the file, whose absolute path you want to find, is in the
$PATH
variable:Based on the above I can conclude that:
realpath -e
andreadlink -e
can be used for finding the absolute path of a file, that we expect to exist in current directory, without result being affected by the$PATH
variable. The only difference is thatrealpath
outputs to stderr, but both will return error code if file is not found:Now in case you want the absolute path a of a file that exists in
$PATH
, the following command would be suitable, independently on whether a file with same name exists in current dir.And a, fallback to
$PATH
if missing, example:在 zsh 中,是的。
假设您的路径存储在变量中,您可以使用
:P
修饰符来获取文件的绝对路径。示例:
上面将打印
../example.txt
的绝对路径。您也可以使用
:A
修饰符来进一步解析符号链接,但这取决于安装的realpath
。请参阅 https://zsh.sourceforge.io/Doc/Release/Expansion.html #修饰符
In zsh, yes there is.
Assuming your path is stored in a variable, you can use the
:P
modifier to get the absolute path of the file.Example:
The above will print the absolute path of
../example.txt
.You can alternatively use the
:A
modifier to further resolve symbolic links, but this depends onrealpath
being installed.See https://zsh.sourceforge.io/Doc/Release/Expansion.html#Modifiers
对于目录,
dirname
因../
被触发并返回./
。nolan6000 的函数可以修改来解决这个问题:
For directories
dirname
gets tripped for../
and returns./
.nolan6000's function can be modified to fix that:
这不是问题的答案,但对于那些编写脚本的人来说:
它正确处理 / .. ./ 等。我似乎也在 OSX 上工作
This is not an answer to the question, but for those who does scripting:
it handles / .. ./ etc correctly. I also seems to work on OSX
我已将以下脚本放置在我的系统上 &当我想快速获取当前目录中文件的完整路径时,我将其称为 bash 别名:
我不确定为什么,但是,在 OS X 上,当脚本“$PWD”调用时,它会扩展为绝对路径。当在命令行上调用 find 命令时,它不会。但这确实是我想要的……享受吧。
I have placed the following script on my system & I call it as a bash alias for when I want to quickly grab the full path to a file in the current dir:
I am not sure why, but, on OS X when called by a script "$PWD" expands to the absolute path. When the find command is called on the command line, it doesn't. But it does what I want... enjoy.
这弥补了
realpath
的缺点,将其存储在shell脚本fullpath
中。您现在可以致电:This makes up for the shortcomings of
realpath
, store it in a shell scriptfullpath
. You can now call:在 Ruby 中获取绝对路径的替代方法:
realpath() {ruby -e "require 'Pathname'; put Pathname.new('$1').realpath.to_s";}< /code>
不使用任何参数(当前文件夹)并使用相对和绝对文件或文件夹路径作为参数。
An alternative to get the absolute path in Ruby:
realpath() {ruby -e "require 'Pathname'; puts Pathname.new('$1').realpath.to_s";}
Works with no arguments (current folder) and relative and absolute file or folder path as agument.
如果您的脚本可能坚持要求存在 bash 或 bash 兼容 shell,那么 Alexander Klimetschek 的答案是可以的。它不适用于仅符合 POSIX 的 shell。
此外,当最终文件是根目录中的文件时,输出将为
//file
,这在技术上并不是不正确的(系统将双/
视为单个文件)但看起来很奇怪。这是一个适用于每个符合 POSIX 标准的 shell 的版本,它使用的所有外部工具也是 POSIX 标准所要求的,并且它显式处理根文件情况:
将其放入文件中并使其可执行,您就拥有了一个 CLI 工具快速获取文件和目录的绝对路径。或者只是复制该函数并在您自己的符合 POSIX 的脚本中使用它。它将相对路径转换为绝对路径并按原样返回绝对路径。
有趣的修改:
如果将行
result=$(cd "$dir" && pwd)
替换为result=$(cd "$dir" && pwd -P )
,那么最终文件路径中的所有符号链接也会被解析。如果您对第一个修改不感兴趣,您可以通过提前返回来优化绝对情况:
并且由于会出现问题:为什么使用
printf
而不是echo
?echo
主要用于将用户的消息打印到标准输出。脚本编写者所依赖的许多echo
行为实际上是未指定的。甚至著名的-n
或制表符\t
的使用都没有标准化。 POSIX 标准规定:要写入标准输出的字符串。如果第一个操作数是 -n,或者任何操作数包含字符,则结果由实现定义。
- https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo .html
因此,每当您想向标准输出写入内容并且不是为了向用户打印消息时,建议使用
printf
作为printf 的行为
已准确定义。我的函数使用 stdout 传递结果,这不是给用户的消息,因此仅使用 printf 才能保证完美的可移植性。The answer of Alexander Klimetschek is okay if your script may insist on a bash or bash compatible shell being present. It won't work with a shell that is only POSIX conforming.
Also when the final file is a file in root, the output will be
//file
, which is not technically incorrect (double/
are treated like single ones by the system) but it looks strange.Here's a version that works with every POSIX conforming shell, all external tools it is using are also required by the POSIX standard, and it explicitly handles the root-file case:
Put that into a file and make it executable and you have a CLI tool to quickly get the absolute path of files and directories. Or just copy the function and use it in your own POSIX conforming scripts. It turns relative paths into absolute ones and returns absolute ones as is.
Interesting modifications:
If you replace the line
result=$(cd "$dir" && pwd)
withresult=$(cd "$dir" && pwd -P)
, then all symbolic links in the path to the final file are resolved as well.If you are not interested into the first modification, you can optimize the absolute case by returning early:
And since the question will arise: Why
printf
instead ofecho
?echo
is intended primary to print messages for the user to stdout. A lot ofecho
behavior that script writers rely on is in fact unspecified. Not even the famous-n
is standardized or the usage of\t
for tab. The POSIX standard says:A string to be written to standard output. If the first operand is -n, or if any of the operands contain a character, the results are implementation-defined.
- https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html
Thus whenever you want to write something to stdout and it's not for the purpose of printing a message to the user, the recommendation is to use
printf
as the behavior ofprintf
is exactly defined. My function uses stdout to pass out a result, this is not a message for the user and thus only usingprintf
guarantees perfect portability.在 bash 中:
也适用于通配符
in bash this:
works also with wild card
我使用单行
但是,这只能在
$FILENAME
具有实际存在的任何类型(相对或绝对)的前导路径时使用。如果根本没有引导路径,那么答案就是$PWD
。如果引导路径不存在,则答案可能是不确定的,否则,如果路径是绝对路径,则答案只是${FILENAME%/*}
。将所有这些放在一起,我建议使用以下函数
另请注意,这仅适用于 bash 和兼容的 shell。我不相信这些替换在简单的 shell
sh
中起作用。I use the single line
However, this can only be used when
$FILENAME
has a leading path of any kind (relative or absolute) that actually exists. If there is no leading path at all, then the answer is simply$PWD
. If the leading path does not exist, then the answer may be indeterminate, otherwise and the answer is simply${FILENAME%/*}
if the path is absolute.Putting this all together I would suggest using the following function
Note also that this only work in
bash
and compatible shells. I don't believe the substitutions work in the simple shellsh
.嘿伙计们,我知道这是一个旧线程,但我只是发布此内容以供像我一样访问过此内容的其他人参考。如果我正确理解了这个问题,我认为是
locate $filename
命令。它显示所提供文件的绝对路径,但前提是该文件存在。Hey guys I know it's an old thread but I am just posting this for reference to anybody else who visited this like me. If i understood the question correctly, I think the
locate $filename
command. It displays the absolute path of the file supplied, but only if it exists.