是否有一个命令来检索给定相对路径的绝对路径?
例如,我想要$line包含dir ./etc/中每个文件的绝对路径
find ./ -type f | while read line; do
echo $line
done
是否有一个命令来检索给定相对路径的绝对路径?
例如,我想要$line包含dir ./etc/中每个文件的绝对路径
find ./ -type f | while read line; do
echo $line
done
当前回答
类似于@ernest-a的答案,但不影响$OLDPWD或定义一个新函数,您可以触发一个子shell (cd <path>;pwd)
$ pwd
/etc/apache2
$ cd ../cups
$ cd -
/etc/apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups
其他回答
realpath试试。
~ $ sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
要避免扩展符号链接,请使用realpath -s。
答案来自“bash/fish命令打印文件的绝对路径”。
我最喜欢的解决方案是@EugenKonkov的解决方案,因为它没有暗示其他实用程序的存在(coreutils包)。
但是对于相对路径“.”和“..”它失败了,所以这里有一个稍微改进的版本来处理这些特殊情况。
但是,如果用户没有cd到相对路径的父目录的权限,它仍然会失败。
#! /bin/sh
# Takes a path argument and returns it as an absolute path.
# No-op if the path is already absolute.
function to-abs-path {
local target="$1"
if [ "$target" == "." ]; then
echo "$(pwd)"
elif [ "$target" == ".." ]; then
echo "$(dirname "$(pwd)")"
else
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
fi
}
这是来自所有其他解决方案的链式解决方案,例如,当realpath失败时,要么是因为没有安装它,要么是因为它带着错误代码退出,那么,将尝试下一个解决方案,直到它获得正确的路径。
#!/bin/bash
function getabsolutepath() {
local target;
local changedir;
local basedir;
local firstattempt;
target="${1}";
if [ "$target" == "." ];
then
printf "%s" "$(pwd)";
elif [ "$target" == ".." ];
then
printf "%s" "$(dirname "$(pwd)")";
else
changedir="$(dirname "${target}")" && basedir="$(basename "${target}")" && firstattempt="$(cd "${changedir}" && pwd)" && printf "%s/%s" "${firstattempt}" "${basedir}" && return 0;
firstattempt="$(readlink -f "${target}")" && printf "%s" "${firstattempt}" && return 0;
firstattempt="$(realpath "${target}")" && printf "%s" "${firstattempt}" && return 0;
# If everything fails... TRHOW PYTHON ON IT!!!
local fullpath;
local pythoninterpreter;
local pythonexecutables;
local pythonlocations;
pythoninterpreter="python";
declare -a pythonlocations=("/usr/bin" "/bin");
declare -a pythonexecutables=("python" "python2" "python3");
for path in "${pythonlocations[@]}";
do
for executable in "${pythonexecutables[@]}";
do
fullpath="${path}/${executable}";
if [[ -f "${fullpath}" ]];
then
# printf "Found ${fullpath}\\n";
pythoninterpreter="${fullpath}";
break;
fi;
done;
if [[ "${pythoninterpreter}" != "python" ]];
then
# printf "Breaking... ${pythoninterpreter}\\n"
break;
fi;
done;
firstattempt="$(${pythoninterpreter} -c "import os, sys; print( os.path.abspath( sys.argv[1] ) );" "${target}")" && printf "%s" "${firstattempt}" && return 0;
# printf "Error: Could not determine the absolute path!\\n";
return 1;
fi
}
printf "\\nResults:\\n%s\\nExit: %s\\n" "$(getabsolutepath "./asdfasdf/ asdfasdf")" "${?}"
基于@EugenKonkov的回答和@HashChange的回答,我的回答结合了前者的简洁和对。和. .关于后者。我相信下面所有的选项仅仅依赖于基本的Shell命令语言POSIX标准。
使用dirname和basename,一个选项是:
absPathDirname()
{
[ -d "${1}" ] && set -- "${1}" || set -- "`dirname "${1}"`" "/`basename "${1}"`"
echo "`cd "${1}"; pwd`${2}";
}
不使用dirname或basename,另一个简单的选项是:
absPathMinusD()
{
[ -d "${1}" ] && set -- "${1}" || set -- "${1%${1##*/}}" "/${1##*/}"
echo "`cd "${1:-.}"; pwd`${2}";
}
我会推荐上面两个选择中的一个,其他的只是为了好玩…
Grep版本:
absPathGrep()
{
echo "`[ "${1##/*}" ] && echo "$1" | grep -Eo '^(.*/)?\.\.($|/)' | { read d && cd "$d"; echo "${PWD}/${1#$d}"; } || echo "$1"`"
}
作为一个有趣的“可以用shell有限的RegEx做什么”的例子:
absPathShellReplace()
{
E="${1##*/}"; D="${E#$E${E#.}}"; DD="${D#$D${D#..}}"
DIR="${1%$E}${E#$DD}"; FILE="${1#$DIR}"; SEP=${FILE:+/}
echo "`cd "${DIR:-.}"; pwd`${SEP#$DIR}$FILE"
}
不管怎样,我投票给了被选中的答案,但我想分享一个解决方案。缺点是,它只适用于Linux——在出现堆栈溢出之前,我花了大约5分钟的时间试图找到OSX的等效版本。但我相信它就在那里。
在Linux上,可以将readlink -e与dirname结合使用。
$(dirname $(readlink -e ../../../../etc/passwd))
收益率
/etc/
然后你用dirname的姐妹,basename 文件名
$(basename ../../../../../passwd)
收益率
passwd
把它们放在一起…
F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"
收益率
/etc/passwd
如果目标目录是安全的,basename将不会返回任何内容 在最终输出中,你只会得到双斜杠。