问题:是否有一个简单的sh / bash / zsh / fish / ...命令来打印我提供给它的文件的绝对路径?
用法案例:我在目录/a/b
中,我想在命令行上打印文件c
的完整路径,以便我可以轻松地将其粘贴到另一个程序中:{ {1}}。简单但是一个小程序可以在处理长路径时节省大约5秒钟,这最终会增加。所以让我感到惊讶的是,我找不到一个标准的实用工具来做到这一点 - 真的没有吗?
这是一个示例实现,abspath.py:
/a/b/c
答案 0 :(得分:429)
尝试realpath
。
$ realpath example.txt
/home/username/example.txt
答案 1 :(得分:294)
尝试解析符号链接的readlink
:
readlink -e /foo/bar/baz
答案 2 :(得分:223)
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
答案 3 :(得分:73)
$ readlink -m FILE
/path/to/FILE
这比readlink -e FILE
或realpath
更好,因为即使文件不存在也能正常工作。
答案 4 :(得分:73)
忘记您系统上可能安装或未安装的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")
该解决方案利用了这样一个事实:当没有参数调用时,Bash内置pwd
命令将打印当前目录的绝对路径。
它是可移植的,不需要readlink
或realpath
,这在给定的Linux / Unix发行版的默认安装中通常不存在。
如上所述,如果给定的目录路径不存在,函数将失败并在stderr上打印。这可能不是你想要的。您可以扩展该功能以处理这种情况:
#!/bin/bash
get_abs_filename() {
# $1 : relative filename
if [ -d "$(dirname "$1")" ]; then
echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
fi
}
现在,如果父目录不存在,它将返回一个空字符串。
嗯,在这种情况下确实给出了绝对路径,但不是最小路径。它看起来像:
/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
}
答案 5 :(得分:58)
此绝对路径转换器的相对路径 shell函数
cd
和pwd
)..
和.
代码:
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
注意:这取决于答案from nolan6000和bsingh,但修复了文件大小写。
我也理解原始问题是关于现有的命令行实用程序。但是因为这似乎是stackoverflow的问题,包括想要具有最小依赖性的shell脚本,我把这个脚本解决方案放在这里,所以我可以在以后找到它:)
答案 6 :(得分:23)
find
命令可能有帮助
find $PWD -name ex*
find $PWD -name example.log
列出当前目录中或下面的所有文件,其名称与模式匹配。如果您只获得一些结果(例如,包含少量文件的树底部附近的目录),则可以简化它,只需
find $PWD
我在Solaris 10上使用它,它没有提到其他实用程序。
答案 7 :(得分:14)
如果你没有readlink或realpath实用程序,你可以使用在bash和zsh中工作的以下函数(不确定其余部分)。
abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }
这也适用于不存在的文件(与python函数os.path.abspath
一样)。
不幸的是abspath ./../somefile
没有摆脱这些点。
答案 8 :(得分:9)
这是一个zsh-only函数,我喜欢它的紧凑性。它使用'A'扩展修饰符 - 参见zshexpn(1)。
realpath() { for f in "$@"; do echo ${f}(:A); done }
答案 9 :(得分:7)
文件中通常没有 absolute path
这样的东西(这句话意味着一般可能有多个,因此使用定冠词 不合适)。 absolute path
是从根“/”开始的任何路径,并指定一个没有歧义的文件,与工作目录无关。(参见例如wikipedia)。
relative path
是从另一个目录开始解释的路径。如果它是由应用程序操纵的relative path
,它可能是工作目录
(虽然不一定)。当它位于目录中的符号链接时,通常是相对于该目录(尽管用户可能还有其他用途)。
因此,绝对路径只是相对于根目录的路径。
路径(绝对路径或相对路径)可能包含也可能不包含符号链接。如果不是这样,它在某种程度上也不受链接结构变化的影响,但这不是必需的,甚至不是必需的。有些人将canonical path
(或canonical file name
或resolved path
)称为absolute path
,其中所有符号链接都已解析,即已被替换为链接到的路径。命令realpath
和readlink
都查找规范路径,但只有realpath
可以选择获取绝对路径而无需解决符号链接(以及其他几个选项)一种路径,绝对或相对于某个目录。)
这需要几个评论:
realpath
和readlink
可以选择对此进行说明。canonical
。因此,概念是时间(或环境)依赖。canonical path
原因:
ro
)在几个挂载点上。因此,即使对canonical path
的限制性更强,也可能存在一些文件的规范路径。这也意味着限定符canonical
有些不足,因为它通常意味着唯一性的概念。
这在Bash: retrieve absolute path given relative
的另一个类似问题的答案中扩展了对该主题的简短讨论我的结论是realpath
设计得更好,比readlink
更灵活。
readlink
未涵盖realpath
的唯一用途是没有选项的调用返回符号链接的值。
答案 10 :(得分:3)
dogbane
answer及其描述内容:
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
说明:
"$1"
dirname "$1"
cd "$(dirname "$1")
进入这个相对目录并通过运行pwd
shell命令获取它的绝对路径$(basename "$1")
echo
答案 11 :(得分:2)
对于目标dirname
,../
会被触发并返回./
。
get_abs_filename() {
# $1 : relative filename
if [ -d "${1%/*}" ]; then
echo "$(cd ${1%/*}; pwd)/${1##*/}"
fi
}
答案 12 :(得分:2)
这不是问题的答案,而是针对那些编写脚本的人:
echo `cd "$1" 2>/dev/null&&pwd||(cd "$(dirname "$1")";pwd|sed "s|/*\$|/${1##*/}|")`
正确处理/ ../等。我似乎也在OSX上工作
答案 13 :(得分:2)
我已将以下脚本放在我的系统&当我想快速获取当前目录中文件的完整路径时,我将其称为bash别名:
#!/bin/bash
/usr/bin/find "$PWD" -maxdepth 1 -mindepth 1 -name "$1"
我不知道为什么,但是,在OS X上调用脚本时,“$ PWD”会扩展到绝对路径。在命令行上调用find命令时,它不会。但它做了我想要的......享受。
答案 14 :(得分:1)
#! /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 "a a"
/home/user/a a
$ fullpath ~/a\ a
/home/user/a a
$ fullpath A
A: No such file or directory.
答案 15 :(得分:1)
获取 Ruby 中的绝对路径的替代方法:
realpath() {ruby -e "require 'Pathname'; puts Pathname.new('$1').realpath.to_s";}
不使用参数(当前文件夹)以及相对和绝对文件或文件夹路径作为文件。
答案 16 :(得分:0)
realpath
是最好的答案,但是如果您没有安装它,则必须首先运行brew install coreutils
,它将安装coreutils并具有许多很棒的功能。编写自定义函数并将其导出会产生大量工作,并且会出现诸如此类的错误,这是两行:
$ brew install coreutils
$ realpath your-file-name.json
答案 17 :(得分:0)
如果您的脚本可能坚持存在bash或bash兼容shell,那么Alexander Klimetschek的答案是可以的。不适用于仅符合POSIX的外壳。
另外,当最终文件是根目录中的文件时,输出将为//file
,从技术上讲这不是错误的(系统将双/
视为单个#!/bin/sh
abspath ( ) {
if [ ! -e "$1" ]; then
return 1
fi
file=""
dir="$1"
if [ ! -d "$dir" ]; then
file=$(basename "$dir")
dir=$(dirname "$dir")
fi
case "$dir" in
/*) ;;
*) dir="$(pwd)/$dir"
esac
result=$(cd "$dir" && pwd)
if [ -n "$file" ]; then
case "$result" in
*/) ;;
*) result="$result/"
esac
result="$result$file"
fi
printf "%s\n" "$result"
}
abspath "$1"
),但看起来很奇怪。
这是一个适用于每个符合POSIX的shell的版本,POSIX标准也需要它使用的所有外部工具,并且它显式处理根文件的情况:
result=$(cd "$dir" && pwd)
将其放入文件中并使其可执行,您有了CLI工具,可以快速获取文件和目录的绝对路径。或者只是复制该函数并在您自己的符合POSIX的脚本中使用它。它将相对路径转换为绝对路径,并按原样返回绝对路径。
有趣的修改
如果将result=$(cd "$dir" && pwd -P)
行替换为abspath ( ) {
if [ ! -e "$1" ]; then
return 1
fi
case "$1" in
/*)
printf "%s\n" "$1"
return 0
esac
file=""
dir="$1"
if [ ! -d "$dir" ]; then
file=$(basename "$dir")
dir=$(dirname "$dir")
fi
result=$(cd "$dir" && pwd)
if [ -n "$file" ]; then
case "$result" in
*/) ;;
*) result="$result/"
esac
result="$result$file"
fi
printf "%s\n" "$result"
}
,则最终文件路径中的所有符号链接也会被解析。
如果您对第一个修改不感兴趣,可以通过尽早返回来优化绝对大小写:
printf
既然会出现问题:为什么用echo
而不是echo
?
echo
主要用于打印消息以供用户输出。实际上,脚本作者所依赖的许多-n
行为是未指定的。甚至没有著名的\t
或选项卡使用printf
的标准化。 POSIX标准说:
要写入标准输出的字符串。如果第一个操作数是-n,或者任何一个操作数包含一个字符,则结果是实现定义的。
-https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html
因此,每当您要写一些东西到stdout而不是为了向用户打印消息时,建议使用printf
,因为printf
的行为已被准确定义。我的函数使用stdout传递结果,这不是给用户的消息,因此仅使用pg_total_relation_size('table_name')
可以保证完美的可移植性。
答案 18 :(得分:0)
我使用单行
(cd ${FILENAME%/*}; pwd)
然而,这只能在 $FILENAME
具有实际存在的任何类型(相对或绝对)的前导路径时使用。如果根本没有引导路径,那么答案就是$PWD
。如果前导路径不存在,则答案可能不确定,否则,如果路径是绝对路径,答案就是 ${FILENAME%/*}
。
综合起来,我建议使用以下功能
function abspath() {
# argument 1: file pathname (relative or absolute)
# returns: file pathname (absolute)
if [ "$1" == "${1##*/}" ]; then # no path at all
echo "$PWD"
elif [ "${1:0:1}" == "/" -a "${1/../}" == "$1" ]; then # strictly absolute path
echo "${1%/*}"
else # relative path (may fail if a needed folder is non-existent)
echo "$(cd ${1%/*}; pwd)"
fi
}
另请注意,这只适用于 bash
和兼容的 shell。我不相信替换在简单的 shell sh
中起作用。
答案 19 :(得分:0)
在某些情况下,此问题的最佳答案可能会产生误导。假设您要查找其绝对路径的文件位于 $PATH
变量中:
# node is in $PATH variable
type -P node
# /home/user/.asdf/shims/node
cd /tmp
touch node
readlink -e node
# /tmp/node
readlink -m node
# /tmp/node
readlink -f node
# /tmp/node
echo "$(cd "$(dirname "node")"; pwd -P)/$(basename "node")"
# /tmp/node
realpath node
# /tmp/node
realpath -e node
# /tmp/node
# Now let's say that for some reason node does not exist in current directory
rm node
readlink -e node
# <nothing printed>
readlink -m node
# /tmp/node # Note: /tmp/node does not exist, but is printed
readlink -f node
# /tmp/node # Note: /tmp/node does not exist, but is printed
echo "$(cd "$(dirname "node")"; pwd -P)/$(basename "node")"
# /tmp/node # Note: /tmp/node does not exist, but is printed
realpath node
# /tmp/node # Note: /tmp/node does not exist, but is printed
realpath -e node
# realpath: node: No such file or directory
基于以上,我可以得出结论:realpath -e
和 readlink -e
可用于查找我们希望存在于当前目录中的文件的绝对路径 , 结果不受$PATH
变量的影响。唯一的区别是 realpath
输出到 stderr,但如果找不到文件,两者都会返回错误代码:
cd /tmp
rm node
realpath -e node ; echo $?
# realpath: node: No such file or directory
# 1
readlink -e node ; echo $?
# 1
现在,如果您想要$PATH
中存在的文件的绝对路径 a,则以下命令将适用,与当前目录中是否存在同名文件无关.
type -P example.txt
# /path/to/example.txt
# Or if you want to follow links
readlink -e $(type -P example.txt)
# /originalpath/to/example.txt
# If the file you are looking for is an executable (and wrap again through `readlink -e` for following links )
which executablefile
# /opt/bin/executablefile
还有一个,如果丢失则回退到 $PATH
,例如:
cd /tmp
touch node
echo $(readlink -e node || type -P node)
# /tmp/node
rm node
echo $(readlink -e node || type -P node)
# /home/user/.asdf/shims/node
答案 20 :(得分:-1)
嘿伙计们,我知道这是一个老线程,但我只是张贴这个,以供参考像我这样访问过此人的任何人。如果我正确理解了这个问题,我认为是locate $filename
命令。它显示所提供文件的绝对路径,但前提是它存在。
答案 21 :(得分:-1)
如果只想使用内置函数,最简单的方法可能是:
find `pwd` -name fileName
仅需键入两个额外的单词,这将在所有unix系统以及OSX上正常工作。