我想转换/foo/bar/../ foo
是否有bash命令可以做到这一点?
编辑:在我的实际案例中,目录确实存在。
我想转换/foo/bar/../ foo
是否有bash命令可以做到这一点?
编辑:在我的实际案例中,目录确实存在。
当前回答
基于@Andre的回答,我可能有一个稍微更好的版本,以防有人在一个无循环,完全基于字符串操作的解决方案。对于那些不想取消对任何符号链接的引用(这是使用realpath或readlink -f的缺点)的人来说,它也很有用。
它适用于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
其他回答
Readlink是用于获取绝对路径的bash标准。如果路径或路径不存在(给定了这样做的标志),它还具有返回空字符串的优点。
要获得一个目录的绝对路径,该目录可能存在,也可能不存在,但其父目录确实存在,请使用:
abspath=$(readlink -f $path)
获取一个必须与所有父目录一起存在的目录的绝对路径:
abspath=$(readlink -e $path)
规范化给定的路径并遵循符号链接,如果它们恰好存在,但忽略丢失的目录,无论如何只返回路径,它是:
abspath=$(readlink -m $path)
唯一的缺点是readlink将跟随链接。如果你不想遵循链接,你可以使用这个替代约定:
abspath=$(cd ${path%/*} && echo $PWD/${path##*/})
这将chdir到$path的目录部分,并打印当前目录和$path的文件部分。如果它不能进行chdir,则会得到一个空字符串,并在stderr上报错。
如果您想要从路径中删除部分文件名,“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
realpath替代品
如果您的shell不支持realpath,您可以尝试
readlink -f /path/here/..
Also
readlink -m /path/there/../../
工作原理与
realpath -s /path/here/../../
在这种情况下,路径不需要存在就可以被规范化。
由于所介绍的解决方案都不适合我,所以在文件不存在的情况下,我实现了我的想法。 André Anjos的解决方案有一个问题,路径以../../都解决错了。例如../../a/b/变成了a/b/。
function normalize_rel_path(){
local path=$1
result=""
IFS='/' read -r -a array <<< "$path"
i=0
for (( idx=${#array[@]}-1 ; idx>=0 ; idx-- )) ; do
c="${array[idx]}"
if [ -z "$c" ] || [[ "$c" == "." ]];
then
continue
fi
if [[ "$c" == ".." ]]
then
i=$((i+1))
elif [ "$i" -gt "0" ];
then
i=$((i-1))
else
if [ -z "$result" ];
then
result=$c
else
result=$c/$result
fi
fi
done
while [ "$i" -gt "0" ]; do
i=$((i-1))
result="../"$result
done
unset IFS
echo $result
}
基于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
我来晚了,但这是我在阅读了一堆这样的帖子后精心设计的解决方案:
resolve_dir() {
(builtin cd `dirname "${1/#~/$HOME}"`'/'`basename "${1/#~/$HOME}"` 2>/dev/null; if [ $? -eq 0 ]; then pwd; fi)
}
这将解析$1的绝对路径,很好地处理~,将符号链接保留在它们所在的路径中,并且不会打乱目录堆栈。它返回完整的路径,如果不存在则不返回。它期望$1是一个目录,如果不是的话可能会失败,但这是一个很容易自己做的检查。