I want to transform /foo/bar/..
to /foo
我想转换/foo/bar/。/ foo
Is there a bash command which does this?
是否有一个bash命令来执行这个操作?
Edit: in my practical case, the directory does exist.
编辑:在我的实际案例中,目录确实存在。
20 个解决方案
#1
145
if you're wanting to chomp part of a filename from the path, "dirname" and "basename" are your friends, and "realpath" is handy too.
如果您想要从路径中删除文件名,“dirname”和“basename”是您的朋友,“realpath”也很方便。
dirname /foo/bar/baz
# /foo/bar
basename /foo/bar/baz
# baz
dirname $( dirname /foo/bar/baz ))
# /foo
realpath ../foo
# ../foo: No such file or directory
realpath /tmp/../tmp/../tmp
# /tmp
Edit
编辑
Realpath appears not to be standard issue.
Realpath似乎不是标准问题。
The closest you can get with the stock standard is
你最接近股票标准的是。
readlink -f /path/here/..
Realpath appears to come from debian, and is not part of coreutils: http://packages.debian.org/unstable/utils/realpath Which was originally part of the DWWW package.
Realpath似乎来自debian,它不是coreutils的一部分:http://packages.debian.org/unstable/utils/realpath,它最初是DWWW包的一部分。
( also available on gentoo as app-admin/realpath )
(也可用于gentoo as app-admin/realpath)
readlink -m /path/there/../../
Works the same as
一样的工作
realpath -s /path/here/../../
in that it doesn't need the path to actually exist to normalise it.
在这一点上,它不需要路径来实现它的正常化。
#2
80
I don't know if there is a direct bash command to do this, but I usually do
我不知道是否有直接的bash命令来执行这个操作,但我通常会这样做。
normalDir="`cd "${dirToNormalize}";pwd`"
echo "${normalDir}"
and it works well.
它工作得很好。
#3
51
Try realpath
. Below is the source in its entirety, hereby donated to the public domain.
realpath试试。下面是它的全部来源,特此捐赠给公共领域。
// realpath.c: display the absolute path to a file or directory.
// Adam Liss, August, 2007
// This program is provided "as-is" to the public domain, without express or
// implied warranty, for any non-profit use, provided this notice is maintained.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <limits.h>
static char *s_pMyName;
void usage(void);
int main(int argc, char *argv[])
{
char
sPath[PATH_MAX];
s_pMyName = strdup(basename(argv[0]));
if (argc < 2)
usage();
printf("%s\n", realpath(argv[1], sPath));
return 0;
}
void usage(void)
{
fprintf(stderr, "usage: %s PATH\n", s_pMyName);
exit(1);
}
#4
35
Use the readlink utility from the coreutils package.
使用coreutils包中的readlink实用程序。
MY_PATH=$(readlink -f "$0")
#5
30
A portable and reliable solution is to use python, which is preinstalled pretty much everywhere (including Darwin). You have two options:
一个可移植和可靠的解决方案是使用python,它在任何地方都是预先安装的(包括Darwin)。你有两个选择:
-
abspath
returns an absolute path but does not resolve symlinks:abspath返回一个绝对路径,但不解析符号链接:
python -c "import os,sys; print os.path.abspath(sys.argv[1])" path/to/file
python - c”导入系统,系统;打印os.path.abspath(sys.argv[1])”路径/ /文件
-
realpath
returns an absolute path and in doing so resolves symlinks, generating a canonical path:realpath返回一个绝对路径,并在此过程中解析符号链接,生成规范路径:
python -c "import os,sys; print os.path.realpath(sys.argv[1])" path/to/file
python - c”导入系统,系统;打印os.path.realpath(sys.argv[1])”路径/ /文件
In each case, path/to/file
can be either a relative or absolute path.
在每种情况下,path/to/文件都可以是相对的,也可以是绝对路径。
#6
13
readlink
is the bash standard for obtaining the absolute path. It also has the advantage of returning empty strings if paths or a path doesn't exist (given the flags to do so).
readlink是获取绝对路径的bash标准。它还具有返回空字符串的优势,如果路径或路径不存在(给定标记这样做)。
To get the absolute path to a directory that may or may not exist, but who's parents do exist, use:
为了获得一个目录的绝对路径,该目录可能存在,也可能不存在,但是谁的父母确实存在,使用:
abspath=$(readlink -f $path)
To get the absolute path to a directory that must exist along with all parents:
要获得与所有父母同时存在的目录的绝对路径:
abspath=$(readlink -e $path)
To canonicalise the given path and follow symlinks if they happen to exist, but otherwise ignore missing directories and just return the path anyway, it's:
要将给定的路径规范化,并在它们碰巧存在时遵循符号链接,但是忽略丢失的目录并返回路径,它是:
abspath=$(readlink -m $path)
The only downside is that readlink will follow links. If you do not want to follow links, you can use this alternative convention:
唯一的缺点是readlink会跟随链接。如果您不想遵循链接,您可以使用这个替代约定:
abspath=$(cd ${path%/*} && echo $PWD/${path##*/})
That will chdir to the directory part of $path and print the current directory along with the file part of $path. If it fails to chdir, you get an empty string and an error on stderr.
将chdir指向$path的目录部分,并打印当前目录以及$path的文件部分。如果它失败到chdir,就会得到一个空字符串和stderr上的错误。
#7
7
My recent solution was:
我最近的解决方案是:
pushd foo/bar/..
dir=`pwd`
popd
Based on the answer of Tim Whitcomb.
基于Tim Whitcomb的回答。
#8
5
As Adam Liss noted realpath
is not bundled with every distribution. Which is a shame, because it is the best solution. The provided source code is great, and I will probably start using it now. Here is what I have been using until now, which I share here just for completeness:
正如Adam Liss所指出的,realpath并不是与每个发行版捆绑在一起的。这是一种耻辱,因为它是最好的解决方案。提供的源代码很好,我现在可能会开始使用它。下面是我一直在使用的,我在这里分享的只是为了完整性:
get_abs_path() {
local PARENT_DIR=$(dirname "$1")
cd "$PARENT_DIR"
local ABS_PATH="$(pwd)"/"$(basename "$1")"
cd - >/dev/null
echo "$ABS_PATH"
}
If you want it to resolve symlinks, just replace pwd
with pwd -P
.
如果您希望它解决符号链接,只需用pwd -P替换pwd。
#9
4
Talkative, and a bit late answer. I need to write one since I'm stuck on older RHEL4/5. I handles absolute and relative links, and simplifies //, /./ and somedir/../ entries.
多话,有点晚的回答。我需要写一个,因为我被困在老的RHEL4/5。我处理绝对和相对的链接,并简化//。/和somedir / . ./条目。
test -x /usr/bin/readlink || readlink () {
echo $(/bin/ls -l $1 | /bin/cut -d'>' -f 2)
}
test -x /usr/bin/realpath || realpath () {
local PATH=/bin:/usr/bin
local inputpath=$1
local changemade=1
while [ $changemade -ne 0 ]
do
changemade=0
local realpath=""
local token=
for token in ${inputpath//\// }
do
case $token in
""|".") # noop
;;
"..") # up one directory
changemade=1
realpath=$(dirname $realpath)
;;
*)
if [ -h $realpath/$token ]
then
changemade=1
target=`readlink $realpath/$token`
if [ "${target:0:1}" = '/' ]
then
realpath=$target
else
realpath="$realpath/$target"
fi
else
realpath="$realpath/$token"
fi
;;
esac
done
inputpath=$realpath
done
echo $realpath
}
mkdir -p /tmp/bar
(cd /tmp ; ln -s /tmp/bar foo; ln -s ../.././usr /tmp/bar/link2usr)
echo `realpath /tmp/foo`
#10
4
Not exactly an answer but perhaps a follow-up question (original question was not explicit):
这不是一个确切的答案,但可能是一个后续问题(最初的问题不明确):
readlink
is fine if you actually want to follow symlinks. But there is also a use case for merely normalizing ./
and ../
and //
sequences, which can be done purely syntactically, without canonicalizing symlinks. readlink
is no good for this, and neither is realpath
.
如果您想要遵循符号链接,那么readlink就很好。但也有一个用例仅仅是为了规范。/和//序列,它可以完全从语法上进行,没有规范化的符号链接。readlink对这一点没有好处,realpath也不是。
for f in $paths; do (cd $f; pwd); done
works for existing paths, but breaks for others.
对现有路径有效,但对其他路径无效。
A sed
script would seem to be a good bet, except that you cannot iteratively replace sequences (/foo/bar/baz/../..
-> /foo/bar/..
-> /foo
) without using something like Perl, which is not safe to assume on all systems, or using some ugly loop to compare the output of sed
to its input.
一个sed脚本似乎是一个不错的选择,除非您不能迭代地替换序列(/foo/bar/baz/.. .)- > / foo / bar / . .-> /foo)不使用类似Perl的东西,这在所有系统上都是不安全的,或者使用一些丑陋的循环来比较sed的输出结果。
FWIW, a one-liner using Java (JDK 6+):
FWIW,一种使用Java (JDK 6+)的单行代码:
jrunscript -e 'for (var i = 0; i < arguments.length; i++) {println(new java.io.File(new java.io.File(arguments[i]).toURI().normalize()))}' $paths
#11
4
I'm late to the party, but this is the solution I've crafted after reading a bunch of threads like this:
我在派对上迟到了,但这是我在阅读了一大堆这样的帖子后的解决方案:
resolve_dir() {
(builtin cd `dirname "${1/#~/$HOME}"`'/'`basename "${1/#~/$HOME}"` 2>/dev/null; if [ $? -eq 0 ]; then pwd; fi)
}
This will resolve the absolute path of $1, play nice with ~, keep symlinks in the path where they are, and it won't mess with your directory stack. It returns the full path or nothing if it doesn't exist. It expects $1 to be a directory and will probably fail if it's not, but that's an easy check to do yourself.
这将解决$1的绝对路径,与~保持友好关系,在它们所在的路径上保持符号链接,并且不会打乱您的目录堆栈。如果它不存在,它将返回完整的路径。它期望$1是一个目录,如果不是,它很可能会失败,但是这是一个简单的检查。
#12
4
Old question, but there is much simpler way if you are dealing with full path names at the shell level:
老问题,但是如果在shell级别上处理完整路径名,会有更简单的方法:
abspath="$( cd "$path" && pwd )"
As the cd happens in a subshell it does not impact the main script.
当cd在子shell中发生时,它不会影响主脚本。
Two variations, supposing your shell built-in commands accept -L and -P, are:
假设您的shell内置命令接受-L和-P,两个变量是:
abspath="$( cd -P "$path" && pwd -P )" #physical path with resolved symlinks abspath="$( cd -L "$path" && pwd -L )" #logical path preserving symlinks
Personally, I rarely need this later approach unless I'm fascinated with symbolic links for some reason.
就我个人而言,我很少需要这种后来的方法,除非我因为某种原因着迷于符号链接。
FYI: variation on obtaining the starting directory of a script which works even if the script changes it's current directory later on.
FYI:获取一个脚本的起始目录的变体,即使脚本在稍后更改它的当前目录。
name0="$(basename "$0")"; #base name of script dir0="$( cd "$( dirname "$0" )" && pwd )"; #absolute starting dir
The use of CD assures you always have the absolute directory, even if the script is run by commands such as ./script.sh which, without the cd/pwd, often gives just .. Useless if the script does a cd later on.
使用CD确保您始终拥有绝对目录,即使脚本是由诸如./script之类的命令运行的。没有cd/pwd,通常只提供。如果脚本稍后执行一个cd,那就没有用了。
#13
3
Try our new Bash library product realpath-lib that we have placed on GitHub for free and unencumbered use. It's thoroughly documented and makes a great learning tool.
尝试我们的新Bash库产品realpathlib,我们已经将其放置在GitHub上,以获得免费和不受限制的使用。它被详尽地记录下来并成为一个很棒的学习工具。
It resolves local, relative and absolute paths and doesn't have any dependencies except Bash 4+; so it should work just about anywhere. It's free, clean, simple and instructive.
它解决了本地、相对和绝对路径,除了Bash 4+之外没有任何依赖关系;所以它应该在任何地方工作。它是免费的,干净的,简单的和有教育意义的。
You can do:
你能做什么:
get_realpath <absolute|relative|symlink|local file path>
This function is the core of the library:
该函数是库的核心:
function get_realpath() {
if [[ -f "$1" ]]
then
# file *must* exist
if cd "$(echo "${1%/*}")" &>/dev/null
then
# file *may* not be local
# exception is ./file.ext
# try 'cd .; cd -;' *works!*
local tmppwd="$PWD"
cd - &>/dev/null
else
# file *must* be local
local tmppwd="$PWD"
fi
else
# file *cannot* exist
return 1 # failure
fi
# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success
}
It also contains functions to get_dirname, get_filename, get_ stemname and validate_path. Try it across platforms, and help to improve it.
它还包含了get_dirname、get_filename、get_ stemname和validate_path的函数。尝试跨平台,并帮助改进它。
#14
1
The problem with realpath
is that it is not available on BSD (or OSX for that matter). Here is a simple recipe extracted from a rather old (2009) article from Linux Journal, that is quite portable:
realpath的问题是它不能在BSD(或OSX)上使用。这里有一个简单的食谱,从一个相当古老的(2009年)的Linux日志中摘录,这是非常便携的:
function normpath() {
# Remove all /./ sequences.
local path=${1//\/.\//\/}
# Remove dir/.. sequences.
while [[ $path =~ ([^/][^/]*/\.\./) ]]; do
path=${path/${BASH_REMATCH[0]}/}
done
echo $path
}
Notice this variant also does not require the path to exist.
注意,这个变体也不需要路径存在。
#15
1
Based on @Andre's answer, I might have a slightly better version, in case someone is after a loop-free, completely string-manipulation based solution. It is also useful for those who don't want to dereference any symlinks, which is the downside of using realpath
or readlink -f
.
基于@Andre的回答,我可能会有一个稍微好一点的版本,以防有人在一个无环的、完全基于字符串的解决方案之后。它对于那些不想取消任何符号链接的人也很有用,这是使用realpath或readlink -f的缺点。
It works on bash versions 3.2.25 and higher.
它适用于bash版本3.2.25和更高版本。
shopt -s extglob
normalise_path() {
local path="$1"
# get rid of /../ example: /one/../two to /two
path="${path//\/*([!\/])\/\.\./}"
# get rid of /./ and //* example: /one/.///two to /one/two
path="${path//@(\/\.\/|\/+(\/))//}"
# remove the last '/.'
echo "${path%%/.}"
}
$ normalise_path /home/codemedic/../codemedic////.config
/home/codemedic/.config
#16
0
Based on loveborg's excellent python snippet, I wrote this:
基于loveborg优秀的python代码片段,我写道:
#!/bin/sh
# Version of readlink that follows links to the end; good for Mac OS X
for file in "$@"; do
while [ -h "$file" ]; do
l=`readlink $file`
case "$l" in
/*) file="$l";;
*) file=`dirname "$file"`/"$l"
esac
done
#echo $file
python -c "import os,sys; print os.path.abspath(sys.argv[1])" "$file"
done
#17
0
FILEPATH="file.txt"
echo $(realpath $(dirname $FILEPATH))/$(basename $FILEPATH)
This works even if the file doesn't exist. It does require the directory containing the file to exist.
即使文件不存在,也可以这样做。它确实需要包含文件的目录存在。
#18
0
I know this is an ancient question. I'm still offering an alternative. Recently I met the same issue and found no existing and portable command to do that. So I wrote the following shell script which includes a function that can do the trick.
我知道这是一个古老的问题。我还在提供另一种选择。最近我遇到了同样的问题,发现没有现成的和可移植的命令可以做到这一点。因此,我编写了下面的shell脚本,其中包含一个可以执行这个技巧的函数。
#! /bin/sh
function normalize {
local rc=0
local esed
local ret
if [ "x`uname -o | grep -i 'darwin'`" != "x" ] ; then
esed="sed -E"
else
esed="sed -r"
fi
if [ $# -gt 0 ] ; then
# invalid
if [ "x`echo $1 | grep -E -e '^/\.\.'`" != "x" ] ; then
echo $1
return -1
fi
# convert to absolute path
if [ "x`echo $1 | grep -E -e '^\/'`" == "x" ] ; then
normalize "`pwd`/$1"
return $?
fi
ret=`echo $1 | $esed 's;/\.($|/);/;g' | $esed 's;/[^/]*[^/.]+[^/]*/\.\.($|/);/;g'`
else
read line
normalize "$line"
return $?
fi
if [ "x`echo $ret | grep -E -e '/\.(/|$)'`" != "x" ] ; then
ret=`normalize "$ret"`
rc=$?
fi
if [ "x`echo $ret | grep -E -e '/\.\.(/|$)'`" != "x" ] ; then
ret=`normalize "$ret"`
rc=$?
fi
echo "$ret"
return $rc
}
https://gist.github.com/bestofsong/8830bdf3e5eb9461d27313c3c282868c
https://gist.github.com/bestofsong/8830bdf3e5eb9461d27313c3c282868c
#19
-1
I discovered today that you can use the stat
command to resolve paths.
我今天发现,您可以使用stat命令来解析路径。
So for a directory like "~/Documents":
所以对于像“~/文档”这样的目录:
You can run this:
您可以运行:
stat -f %N ~/Documents
stat - f % N ~ /文档
To get the full path:
获得完整的路径:
/Users/me/Documents
/用户/我/文档
For symlinks, you can use the %Y format option:
对于符号链接,可以使用%Y格式选项:
stat -f %Y example_symlink
stat - f % Y example_symlink
Which might return a result like:
这可能会返回一个结果:
/usr/local/sbin/example_symlink
/usr/local/sbin/example_symlink
The formatting options might be different on other versions of *NIX but these worked for me on OSX.
在其他版本的*NIX上,格式化选项可能有所不同,但这些在OSX上为我工作。
#20
-3
A simple solution using node.js
:
使用node.js的简单解决方案:
#!/usr/bin/env node
process.stdout.write(require('path').resolve(process.argv[2]));
#1
145
if you're wanting to chomp part of a filename from the path, "dirname" and "basename" are your friends, and "realpath" is handy too.
如果您想要从路径中删除文件名,“dirname”和“basename”是您的朋友,“realpath”也很方便。
dirname /foo/bar/baz
# /foo/bar
basename /foo/bar/baz
# baz
dirname $( dirname /foo/bar/baz ))
# /foo
realpath ../foo
# ../foo: No such file or directory
realpath /tmp/../tmp/../tmp
# /tmp
Edit
编辑
Realpath appears not to be standard issue.
Realpath似乎不是标准问题。
The closest you can get with the stock standard is
你最接近股票标准的是。
readlink -f /path/here/..
Realpath appears to come from debian, and is not part of coreutils: http://packages.debian.org/unstable/utils/realpath Which was originally part of the DWWW package.
Realpath似乎来自debian,它不是coreutils的一部分:http://packages.debian.org/unstable/utils/realpath,它最初是DWWW包的一部分。
( also available on gentoo as app-admin/realpath )
(也可用于gentoo as app-admin/realpath)
readlink -m /path/there/../../
Works the same as
一样的工作
realpath -s /path/here/../../
in that it doesn't need the path to actually exist to normalise it.
在这一点上,它不需要路径来实现它的正常化。
#2
80
I don't know if there is a direct bash command to do this, but I usually do
我不知道是否有直接的bash命令来执行这个操作,但我通常会这样做。
normalDir="`cd "${dirToNormalize}";pwd`"
echo "${normalDir}"
and it works well.
它工作得很好。
#3
51
Try realpath
. Below is the source in its entirety, hereby donated to the public domain.
realpath试试。下面是它的全部来源,特此捐赠给公共领域。
// realpath.c: display the absolute path to a file or directory.
// Adam Liss, August, 2007
// This program is provided "as-is" to the public domain, without express or
// implied warranty, for any non-profit use, provided this notice is maintained.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <limits.h>
static char *s_pMyName;
void usage(void);
int main(int argc, char *argv[])
{
char
sPath[PATH_MAX];
s_pMyName = strdup(basename(argv[0]));
if (argc < 2)
usage();
printf("%s\n", realpath(argv[1], sPath));
return 0;
}
void usage(void)
{
fprintf(stderr, "usage: %s PATH\n", s_pMyName);
exit(1);
}
#4
35
Use the readlink utility from the coreutils package.
使用coreutils包中的readlink实用程序。
MY_PATH=$(readlink -f "$0")
#5
30
A portable and reliable solution is to use python, which is preinstalled pretty much everywhere (including Darwin). You have two options:
一个可移植和可靠的解决方案是使用python,它在任何地方都是预先安装的(包括Darwin)。你有两个选择:
-
abspath
returns an absolute path but does not resolve symlinks:abspath返回一个绝对路径,但不解析符号链接:
python -c "import os,sys; print os.path.abspath(sys.argv[1])" path/to/file
python - c”导入系统,系统;打印os.path.abspath(sys.argv[1])”路径/ /文件
-
realpath
returns an absolute path and in doing so resolves symlinks, generating a canonical path:realpath返回一个绝对路径,并在此过程中解析符号链接,生成规范路径:
python -c "import os,sys; print os.path.realpath(sys.argv[1])" path/to/file
python - c”导入系统,系统;打印os.path.realpath(sys.argv[1])”路径/ /文件
In each case, path/to/file
can be either a relative or absolute path.
在每种情况下,path/to/文件都可以是相对的,也可以是绝对路径。
#6
13
readlink
is the bash standard for obtaining the absolute path. It also has the advantage of returning empty strings if paths or a path doesn't exist (given the flags to do so).
readlink是获取绝对路径的bash标准。它还具有返回空字符串的优势,如果路径或路径不存在(给定标记这样做)。
To get the absolute path to a directory that may or may not exist, but who's parents do exist, use:
为了获得一个目录的绝对路径,该目录可能存在,也可能不存在,但是谁的父母确实存在,使用:
abspath=$(readlink -f $path)
To get the absolute path to a directory that must exist along with all parents:
要获得与所有父母同时存在的目录的绝对路径:
abspath=$(readlink -e $path)
To canonicalise the given path and follow symlinks if they happen to exist, but otherwise ignore missing directories and just return the path anyway, it's:
要将给定的路径规范化,并在它们碰巧存在时遵循符号链接,但是忽略丢失的目录并返回路径,它是:
abspath=$(readlink -m $path)
The only downside is that readlink will follow links. If you do not want to follow links, you can use this alternative convention:
唯一的缺点是readlink会跟随链接。如果您不想遵循链接,您可以使用这个替代约定:
abspath=$(cd ${path%/*} && echo $PWD/${path##*/})
That will chdir to the directory part of $path and print the current directory along with the file part of $path. If it fails to chdir, you get an empty string and an error on stderr.
将chdir指向$path的目录部分,并打印当前目录以及$path的文件部分。如果它失败到chdir,就会得到一个空字符串和stderr上的错误。
#7
7
My recent solution was:
我最近的解决方案是:
pushd foo/bar/..
dir=`pwd`
popd
Based on the answer of Tim Whitcomb.
基于Tim Whitcomb的回答。
#8
5
As Adam Liss noted realpath
is not bundled with every distribution. Which is a shame, because it is the best solution. The provided source code is great, and I will probably start using it now. Here is what I have been using until now, which I share here just for completeness:
正如Adam Liss所指出的,realpath并不是与每个发行版捆绑在一起的。这是一种耻辱,因为它是最好的解决方案。提供的源代码很好,我现在可能会开始使用它。下面是我一直在使用的,我在这里分享的只是为了完整性:
get_abs_path() {
local PARENT_DIR=$(dirname "$1")
cd "$PARENT_DIR"
local ABS_PATH="$(pwd)"/"$(basename "$1")"
cd - >/dev/null
echo "$ABS_PATH"
}
If you want it to resolve symlinks, just replace pwd
with pwd -P
.
如果您希望它解决符号链接,只需用pwd -P替换pwd。
#9
4
Talkative, and a bit late answer. I need to write one since I'm stuck on older RHEL4/5. I handles absolute and relative links, and simplifies //, /./ and somedir/../ entries.
多话,有点晚的回答。我需要写一个,因为我被困在老的RHEL4/5。我处理绝对和相对的链接,并简化//。/和somedir / . ./条目。
test -x /usr/bin/readlink || readlink () {
echo $(/bin/ls -l $1 | /bin/cut -d'>' -f 2)
}
test -x /usr/bin/realpath || realpath () {
local PATH=/bin:/usr/bin
local inputpath=$1
local changemade=1
while [ $changemade -ne 0 ]
do
changemade=0
local realpath=""
local token=
for token in ${inputpath//\// }
do
case $token in
""|".") # noop
;;
"..") # up one directory
changemade=1
realpath=$(dirname $realpath)
;;
*)
if [ -h $realpath/$token ]
then
changemade=1
target=`readlink $realpath/$token`
if [ "${target:0:1}" = '/' ]
then
realpath=$target
else
realpath="$realpath/$target"
fi
else
realpath="$realpath/$token"
fi
;;
esac
done
inputpath=$realpath
done
echo $realpath
}
mkdir -p /tmp/bar
(cd /tmp ; ln -s /tmp/bar foo; ln -s ../.././usr /tmp/bar/link2usr)
echo `realpath /tmp/foo`
#10
4
Not exactly an answer but perhaps a follow-up question (original question was not explicit):
这不是一个确切的答案,但可能是一个后续问题(最初的问题不明确):
readlink
is fine if you actually want to follow symlinks. But there is also a use case for merely normalizing ./
and ../
and //
sequences, which can be done purely syntactically, without canonicalizing symlinks. readlink
is no good for this, and neither is realpath
.
如果您想要遵循符号链接,那么readlink就很好。但也有一个用例仅仅是为了规范。/和//序列,它可以完全从语法上进行,没有规范化的符号链接。readlink对这一点没有好处,realpath也不是。
for f in $paths; do (cd $f; pwd); done
works for existing paths, but breaks for others.
对现有路径有效,但对其他路径无效。
A sed
script would seem to be a good bet, except that you cannot iteratively replace sequences (/foo/bar/baz/../..
-> /foo/bar/..
-> /foo
) without using something like Perl, which is not safe to assume on all systems, or using some ugly loop to compare the output of sed
to its input.
一个sed脚本似乎是一个不错的选择,除非您不能迭代地替换序列(/foo/bar/baz/.. .)- > / foo / bar / . .-> /foo)不使用类似Perl的东西,这在所有系统上都是不安全的,或者使用一些丑陋的循环来比较sed的输出结果。
FWIW, a one-liner using Java (JDK 6+):
FWIW,一种使用Java (JDK 6+)的单行代码:
jrunscript -e 'for (var i = 0; i < arguments.length; i++) {println(new java.io.File(new java.io.File(arguments[i]).toURI().normalize()))}' $paths
#11
4
I'm late to the party, but this is the solution I've crafted after reading a bunch of threads like this:
我在派对上迟到了,但这是我在阅读了一大堆这样的帖子后的解决方案:
resolve_dir() {
(builtin cd `dirname "${1/#~/$HOME}"`'/'`basename "${1/#~/$HOME}"` 2>/dev/null; if [ $? -eq 0 ]; then pwd; fi)
}
This will resolve the absolute path of $1, play nice with ~, keep symlinks in the path where they are, and it won't mess with your directory stack. It returns the full path or nothing if it doesn't exist. It expects $1 to be a directory and will probably fail if it's not, but that's an easy check to do yourself.
这将解决$1的绝对路径,与~保持友好关系,在它们所在的路径上保持符号链接,并且不会打乱您的目录堆栈。如果它不存在,它将返回完整的路径。它期望$1是一个目录,如果不是,它很可能会失败,但是这是一个简单的检查。
#12
4
Old question, but there is much simpler way if you are dealing with full path names at the shell level:
老问题,但是如果在shell级别上处理完整路径名,会有更简单的方法:
abspath="$( cd "$path" && pwd )"
As the cd happens in a subshell it does not impact the main script.
当cd在子shell中发生时,它不会影响主脚本。
Two variations, supposing your shell built-in commands accept -L and -P, are:
假设您的shell内置命令接受-L和-P,两个变量是:
abspath="$( cd -P "$path" && pwd -P )" #physical path with resolved symlinks abspath="$( cd -L "$path" && pwd -L )" #logical path preserving symlinks
Personally, I rarely need this later approach unless I'm fascinated with symbolic links for some reason.
就我个人而言,我很少需要这种后来的方法,除非我因为某种原因着迷于符号链接。
FYI: variation on obtaining the starting directory of a script which works even if the script changes it's current directory later on.
FYI:获取一个脚本的起始目录的变体,即使脚本在稍后更改它的当前目录。
name0="$(basename "$0")"; #base name of script dir0="$( cd "$( dirname "$0" )" && pwd )"; #absolute starting dir
The use of CD assures you always have the absolute directory, even if the script is run by commands such as ./script.sh which, without the cd/pwd, often gives just .. Useless if the script does a cd later on.
使用CD确保您始终拥有绝对目录,即使脚本是由诸如./script之类的命令运行的。没有cd/pwd,通常只提供。如果脚本稍后执行一个cd,那就没有用了。
#13
3
Try our new Bash library product realpath-lib that we have placed on GitHub for free and unencumbered use. It's thoroughly documented and makes a great learning tool.
尝试我们的新Bash库产品realpathlib,我们已经将其放置在GitHub上,以获得免费和不受限制的使用。它被详尽地记录下来并成为一个很棒的学习工具。
It resolves local, relative and absolute paths and doesn't have any dependencies except Bash 4+; so it should work just about anywhere. It's free, clean, simple and instructive.
它解决了本地、相对和绝对路径,除了Bash 4+之外没有任何依赖关系;所以它应该在任何地方工作。它是免费的,干净的,简单的和有教育意义的。
You can do:
你能做什么:
get_realpath <absolute|relative|symlink|local file path>
This function is the core of the library:
该函数是库的核心:
function get_realpath() {
if [[ -f "$1" ]]
then
# file *must* exist
if cd "$(echo "${1%/*}")" &>/dev/null
then
# file *may* not be local
# exception is ./file.ext
# try 'cd .; cd -;' *works!*
local tmppwd="$PWD"
cd - &>/dev/null
else
# file *must* be local
local tmppwd="$PWD"
fi
else
# file *cannot* exist
return 1 # failure
fi
# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success
}
It also contains functions to get_dirname, get_filename, get_ stemname and validate_path. Try it across platforms, and help to improve it.
它还包含了get_dirname、get_filename、get_ stemname和validate_path的函数。尝试跨平台,并帮助改进它。
#14
1
The problem with realpath
is that it is not available on BSD (or OSX for that matter). Here is a simple recipe extracted from a rather old (2009) article from Linux Journal, that is quite portable:
realpath的问题是它不能在BSD(或OSX)上使用。这里有一个简单的食谱,从一个相当古老的(2009年)的Linux日志中摘录,这是非常便携的:
function normpath() {
# Remove all /./ sequences.
local path=${1//\/.\//\/}
# Remove dir/.. sequences.
while [[ $path =~ ([^/][^/]*/\.\./) ]]; do
path=${path/${BASH_REMATCH[0]}/}
done
echo $path
}
Notice this variant also does not require the path to exist.
注意,这个变体也不需要路径存在。
#15
1
Based on @Andre's answer, I might have a slightly better version, in case someone is after a loop-free, completely string-manipulation based solution. It is also useful for those who don't want to dereference any symlinks, which is the downside of using realpath
or readlink -f
.
基于@Andre的回答,我可能会有一个稍微好一点的版本,以防有人在一个无环的、完全基于字符串的解决方案之后。它对于那些不想取消任何符号链接的人也很有用,这是使用realpath或readlink -f的缺点。
It works on bash versions 3.2.25 and higher.
它适用于bash版本3.2.25和更高版本。
shopt -s extglob
normalise_path() {
local path="$1"
# get rid of /../ example: /one/../two to /two
path="${path//\/*([!\/])\/\.\./}"
# get rid of /./ and //* example: /one/.///two to /one/two
path="${path//@(\/\.\/|\/+(\/))//}"
# remove the last '/.'
echo "${path%%/.}"
}
$ normalise_path /home/codemedic/../codemedic////.config
/home/codemedic/.config
#16
0
Based on loveborg's excellent python snippet, I wrote this:
基于loveborg优秀的python代码片段,我写道:
#!/bin/sh
# Version of readlink that follows links to the end; good for Mac OS X
for file in "$@"; do
while [ -h "$file" ]; do
l=`readlink $file`
case "$l" in
/*) file="$l";;
*) file=`dirname "$file"`/"$l"
esac
done
#echo $file
python -c "import os,sys; print os.path.abspath(sys.argv[1])" "$file"
done
#17
0
FILEPATH="file.txt"
echo $(realpath $(dirname $FILEPATH))/$(basename $FILEPATH)
This works even if the file doesn't exist. It does require the directory containing the file to exist.
即使文件不存在,也可以这样做。它确实需要包含文件的目录存在。
#18
0
I know this is an ancient question. I'm still offering an alternative. Recently I met the same issue and found no existing and portable command to do that. So I wrote the following shell script which includes a function that can do the trick.
我知道这是一个古老的问题。我还在提供另一种选择。最近我遇到了同样的问题,发现没有现成的和可移植的命令可以做到这一点。因此,我编写了下面的shell脚本,其中包含一个可以执行这个技巧的函数。
#! /bin/sh
function normalize {
local rc=0
local esed
local ret
if [ "x`uname -o | grep -i 'darwin'`" != "x" ] ; then
esed="sed -E"
else
esed="sed -r"
fi
if [ $# -gt 0 ] ; then
# invalid
if [ "x`echo $1 | grep -E -e '^/\.\.'`" != "x" ] ; then
echo $1
return -1
fi
# convert to absolute path
if [ "x`echo $1 | grep -E -e '^\/'`" == "x" ] ; then
normalize "`pwd`/$1"
return $?
fi
ret=`echo $1 | $esed 's;/\.($|/);/;g' | $esed 's;/[^/]*[^/.]+[^/]*/\.\.($|/);/;g'`
else
read line
normalize "$line"
return $?
fi
if [ "x`echo $ret | grep -E -e '/\.(/|$)'`" != "x" ] ; then
ret=`normalize "$ret"`
rc=$?
fi
if [ "x`echo $ret | grep -E -e '/\.\.(/|$)'`" != "x" ] ; then
ret=`normalize "$ret"`
rc=$?
fi
echo "$ret"
return $rc
}
https://gist.github.com/bestofsong/8830bdf3e5eb9461d27313c3c282868c
https://gist.github.com/bestofsong/8830bdf3e5eb9461d27313c3c282868c
#19
-1
I discovered today that you can use the stat
command to resolve paths.
我今天发现,您可以使用stat命令来解析路径。
So for a directory like "~/Documents":
所以对于像“~/文档”这样的目录:
You can run this:
您可以运行:
stat -f %N ~/Documents
stat - f % N ~ /文档
To get the full path:
获得完整的路径:
/Users/me/Documents
/用户/我/文档
For symlinks, you can use the %Y format option:
对于符号链接,可以使用%Y格式选项:
stat -f %Y example_symlink
stat - f % Y example_symlink
Which might return a result like:
这可能会返回一个结果:
/usr/local/sbin/example_symlink
/usr/local/sbin/example_symlink
The formatting options might be different on other versions of *NIX but these worked for me on OSX.
在其他版本的*NIX上,格式化选项可能有所不同,但这些在OSX上为我工作。
#20
-3
A simple solution using node.js
:
使用node.js的简单解决方案:
#!/usr/bin/env node
process.stdout.write(require('path').resolve(process.argv[2]));