Bash:检索绝对path给定的相对
是否有一个命令来检索给定相对path的绝对path?
例如,我想$行包含每个文件的绝对path在目录./etc/
find ./ -type f | while read line; do echo $line done
使用:
find $(pwd)/ -type f
获取所有文件或
echo $(pwd)/$line
显示完整path(如果相对path很重要)
如果安装了coreutils软件包,通常可以使用readlink -f relative_file_name
来检索绝对readlink -f relative_file_name
(解决所有符号链接)
尝试realpath
。
~ $ sudo apt-get install realpath ~ $ realpath .bashrc /home/username/.bashrc
答案来自“ bash / fish命令打印文件的绝对path ”。
为了什么是值得的,我投了赞成的答案,但想分享一个解决scheme。 缺点是,它只是Linux – 我花了大约5分钟,试图findOSX等价物之前来到堆栈溢出。 我确定它在那里。
在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
将不会返回任何内容,而最终的输出只会以双斜线结束。
#! /bin/sh echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
UPD一些解释
- 这个脚本获取相对path作为参数
"$1"
- 然后我们得到该path的dirname部分(您可以将dir或文件传递给此脚本):
dirname "$1"
- 然后我们把
cd "$(dirname "$1")
放到这个相对的目录中,并通过运行pwd
shell命令获得它的绝对path - 之后,我们将基本名称追加到绝对path:
$(basename "$1")
- 作为最后一步,我们
echo
它
我认为这是最便携的:
abspath() { cd "$(dirname "$1")" printf "%s/%s\n" "$(pwd)" "$(basename "$1")" cd "$OLDPWD" }
如果path不存在,将会失败。
真正的道路可能是最好的
但是…
最初的问题从一开始就非常混乱,一个与所述问题关系不大的例子。
所选答案实际上回答了所给出的例子,而不是标题中的问题。 第一个命令就是这个答案(是不是真的?我怀疑),而且没有'/'也可以。 我看不到第二个命令在做什么。
几个问题是混合的:
-
将相对path名改为绝对path名,无论它表示什么,可能什么都不是。 ( 通常情况下,如果您发出诸如
touch foo/bar
类的命令,则在真正创build文件之前,path名foo/bar
必须存在,并且可能用于计算。 -
可能有几个绝对path名表示相同的文件(或潜在的文件),尤其是因为path上的符号链接(符号链接),但可能由于其他原因(设备可能被挂载两次,只读)。 有人可能会也可能不想解决这样的符号链接。
-
到达非符号链接文件或名称的符号链接链的末尾。 这可能会或可能不会产生绝对path名称,具体取决于如何完成。 有人可能或不想将其parsing为绝对path名。
readlink foo
without option命令只有在它的参数foo
是一个符号链接时才会给出答案,并且该答案是该符号链接的值。 没有其他的链接。 答案可能是相对path:无论是符号链接参数的值。
但是, readlink
有选项(-f -e或-m),它们可以用于所有文件,并且给一个实际上由参数表示的文件提供一个绝对path名(没有符号链接的那个)。
这适用于任何不是符号链接的东西,尽pipe可能希望使用绝对path名而不parsingpath上的中间符号链接。 这是通过realpath -s foo
命令完成的
在符号链接参数的情况下, readlink
及其选项将再次parsing参数绝对path上的所有符号链接,但是也包括所有可能通过跟随参数值而遇到的符号链接。 如果你希望获得一个符号链接本身的绝对path,而不是它可能链接到的任何东西,你可能不希望这样做。 同样,如果foo
是符号链接, realpath -s foo
将获得绝对path而不parsing符号链接,包括作为参数给出的符号链接。
如果没有-s
选项, realpath
与readlink
几乎相同,只是简单地读取链接的值以及其他一些东西。 我不明白为什么readlink
有它的select,显然创造一个readlink
冗余。
探索networking并不多说,除了系统之间可能会有一些变化。
结论: realpath
是使用最好的命令,具有最大的灵活性,至less在这里要求的使用。
在find
情况下,最简单的方法是给它的绝对path进行search,例如:
find /etc find `pwd`/subdir_of_current_dir/ -type f
如果您在Mac OS X上使用bash,既不存在实际path,也不能使用readlink打印绝对path,您可以select编写自己的版本来打印它。 这是我的实现:
(纯粹的bash)
abspath(){ local thePath if [[ ! "$1" =~ ^/ ]];then thePath="$PWD/$1" else thePath="$1" fi echo "$thePath"|( IFS=/ read -a parr declare -a outp for i in "${parr[@]}";do case "$i" in ''|.) continue ;; ..) len=${#outp[@]} if ((len==0));then continue else unset outp[$((len-1))] fi ;; *) len=${#outp[@]} outp[$len]="$i" ;; esac done echo /"${outp[*]}" ) }
(使用gawk)
abspath_gawk() { if [[ -n "$1" ]];then echo $1|gawk '{ if(substr($0,1,1) != "/"){ path = ENVIRON["PWD"]"/"$0 } else path = $0 split(path, a, "/") n = asorti(a, b,"@ind_num_asc") for(i in a){ if(a[i]=="" || a[i]=="."){ delete a[i] } } n = asorti(a, b, "@ind_num_asc") m = 0 while(m!=n){ m = n for(i=1;i<=n;i++){ if(a[b[i]]==".."){ if(b[i-1] in a){ delete a[b[i-1]] delete a[b[i]] n = asorti(a, b, "@ind_num_asc") break } else exit 1 } } } n = asorti(a, b, "@ind_num_asc") if(n==0){ printf "/" } else { for(i=1;i<=n;i++){ printf "/"a[b[i]] } } }' fi }
(纯粹的bsd awk)
#!/usr/bin/env awk -f function abspath(path, i,j,n,a,b,back,out){ if(substr(path,1,1) != "/"){ path = ENVIRON["PWD"]"/"path } split(path, a, "/") n = length(a) for(i=1;i<=n;i++){ if(a[i]==""||a[i]=="."){ continue } a[++j]=a[i] } for(i=j+1;i<=n;i++){ delete a[i] } j=0 for(i=length(a);i>=1;i--){ if(back==0){ if(a[i]==".."){ back++ continue } else { b[++j]=a[i] } } else { if(a[i]==".."){ back++ continue } else { back-- continue } } } if(length(b)==0){ return "/" } else { for(i=length(b);i>=1;i--){ out=out"/"b[i] } return out } } BEGIN{ if(ARGC>1){ for(k=1;k<ARGC;k++){ print abspath(ARGV[k]) } exit } } { print abspath($0) }
例:
$ abspath I/am/.//..//the/./god/../of///.././war /Users/leon/I/the/war
Eugen的回答对我来说不太合适,但是这样做:
absolute="$(cd $(dirname $file); pwd)/$(basename $file)"
注意,你当前的工作目录不受影响。
他们说,除了find $PWD
或者(在bash中) find ~+
更方便一些。
类似于@ ernest-a的答案,但不影响$OLDPWD
或定义一个新的函数,你可以触发一个子shell (cd <path>; pwd)
$ pwd /etc/apache2 $ cd ../cups $ cd - /etc/apache2 $ (cd ~/..; pwd) /Users $ cd - /etc/cups
如果相对path是目录path,那么试试我的,应该是最好的:
absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null) echo $absPath
回声“mydir / doc / mydir / usoe ./mydir/usm”| awk'{split($ 0,array,“”); (我在数组){系统(“CD”arrays[我]“&&回声$ PWD”)}}'
如果你想把一个包含相对path的variables转换成绝对path,这是有效的:
dir=`cd "$dir"`
“cd”回声而不改变工作目录,因为在这里执行一个子shell。