有没有一条命令可以根据相对路径获取绝对路径?
例如,我想让$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
echo "mydir/doc/ mydir/usoe ./mydir/usm" | awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'
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
命令试图模仿的确切语义。{1..8}
或类似内容。选择数字8是因为多年来Linux的最大限制为8,然后在版本4.2中更改为整个路径的40个分辨率总限制。如果达到分辨率限制,代码不会失败,而是返回上次考虑的路径 - 可以添加显式的[ -L "${FILEPATH}" ]
检查来检测此情况。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}"
line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line
/
作为字符串的一部分查找/替换时,\
字符会将其否定掉。dirname
和 basename
。类似这样的语句:dir=\
dirname $line`; file=`basename $line`; line=`cd $dir; pwd`/$file` - Alexis Wilke基于这个答案,作者为@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}";
}
absPathGrep()
{
echo "`[ "${1##/*}" ] && echo "$1" | grep -Eo '^(.*/)?\.\.($|/)' | { read d && cd "$d"; echo "${PWD}/${1#$d}"; } || echo "$1"`"
}
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"
}
这是一个链接解决方案,例如,当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")" "${?}"
dir=`cd "$dir"`
"cd" 命令在子 shell 中执行,因此只是回显当前工作目录,而不会改变实际的工作目录。
dir=\
cd ".."` && echo $dir`时,shell会打印一个空行。 - Michael