是否有一个命令来检索给定相对路径的绝对路径?
例如,我想要$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
当前回答
下面是一个相当短的函数,可以用来完全绝对化和规范化任何给定的输入路径,只使用POSIX shell和readlink语义:
canonicalize_path() {
(
FILEPATH="$1"
for _ in 1 2 3 4 5 6 7 8; # Maximum symlink recursion depth
do
cd -L "`case "${FILEPATH}" in */*) echo "${FILEPATH%/*}";; *) echo ".";; esac`/" # cd $(dirname)
if ! FILEPATH="$(readlink "${FILEPATH##*/}" || ( echo "${FILEPATH##*/}" && false ) )";
then
break
fi
done
cd -P "." || return $?
echo "$(pwd)/${FILEPATH}"
)
}
如果引用的文件不存在,则只解析指向最终文件名的目录路径。如果指向该文件路径的任何目录都不存在,将返回一个cd错误。这恰好是它试图模拟的GNU/Linux readlink -f命令的确切语义。
在bash/zsh中,您还可以将数字列表压缩为{1..8}或类似的。之所以选择8这个数字,是因为这是Linux多年来的最大限制,后来在4.2版本中将整个路径的分辨率限制为40。如果达到了分辨率限制,代码不会失败,而是返回最后考虑的路径——但是可以添加显式的[- l "${FILEPATH}"]检查来检测这种情况。
这段代码也可以很容易地重用,以确保当前工作目录与已执行脚本在文件系统中的位置匹配(shell脚本的常见需求),只需删除函数和子shell包装器:
FILEPATH="$0"
for _ in 1 2 3 4 5 6 7 8; # Maximum symlink recursion depth
do
cd -L "`case "${FILEPATH}" in */*) echo "${FILEPATH%/*}";; *) echo ".";; esac`/" # cd $(dirname)
if ! FILEPATH="$(readlink "${FILEPATH##*/}" || ( echo "${FILEPATH##*/}" && false ) )";
then
break
fi
done
cd -P "."
FILEPATH="$(pwd)/${FILEPATH}"
其他回答
realpath试试。
~ $ sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
要避免扩展符号链接,请使用realpath -s。
答案来自“bash/fish命令打印文件的绝对路径”。
不管怎样,我投票给了被选中的答案,但我想分享一个解决方案。缺点是,它只适用于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将不会返回任何内容 在最终输出中,你只会得到双斜杠。
这是来自所有其他解决方案的链式解决方案,例如,当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")" "${?}"
如果你已经安装了coreutils包,你通常可以使用readlink -f relative_file_name来检索绝对符号链接(解析所有符号链接)。
如果相对路径是一个目录路径,那么试试我的,应该是最好的:
absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)
echo $absPath