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 -edirname

 $(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一些解释

  1. 这个脚本获取相对path作为参数"$1"
  2. 然后我们得到该path的dirname部分(您可以将dir或文件传递给此脚本): dirname "$1"
  3. 然后我们把cd "$(dirname "$1")放到这个相对的目录中,并通过运行pwd shell命令获得它的绝对path
  4. 之后,我们将基本名称追加到绝对path: $(basename "$1")
  5. 作为最后一步,我们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选项, realpathreadlink几乎相同,只是简单地读取链接的值以及其他一些东西。 我不明白为什么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。