bash/fish命令用于打印文件的绝对路径

dha*_*rdy 405 bash shell path

问题:是否有一个简单的sh/bash/zsh/fish/...命令来打印我提供的文件的绝对路径?

用例:我在目录中/a/b,我想c在命令行上打印文件的完整路径,以便我可以轻松地将其粘贴到另一个程序中:/a/b/c.简单但是一个小程序可以在处理长路径时节省大约5秒钟,这最终会增加.因此,令我惊讶的是,我无法找到标准实用程序来执行此操作 - 真的没有吗?

这是一个示例实现,abspath.py:

#!/usr/bin/python
# Author: Diggory Hardy <diggory.hardy@gmail.com>
# Licence: public domain
# Purpose: print the absolute path of all input paths

import sys
import os.path
if len(sys.argv)>1:
    for i in range(1,len(sys.argv)):
        print os.path.abspath( sys.argv[i] )
    sys.exit(0)
else:
    print >> sys.stderr, "Usage: ",sys.argv[0]," PATH."
    sys.exit(1)
Run Code Online (Sandbox Code Playgroud)

Ben*_*ier 490

试试realpath.

$ realpath example.txt
/home/username/example.txt
Run Code Online (Sandbox Code Playgroud)

  • +1,非常好的程序.但请注意,它是一个外部命令(不是内置的shell),默认情况下可能不会出现在每个系统中,即您可能需要安装它.在Debian中,它位于一个具有相同名称的单独包中. (123认同)
  • @Dalin:尝试安装coreutils.二进制文件名为grealpath. (14认同)
  • 我在我的路径中添加了一个`realpath`,其中包括:https://github.com/westonruter/misc-cli-tools/blob/master/realpath (5认同)
  • @WalterTross,它可以通过 Homebrew 从“coreutils”公式中获得。 (5认同)
  • 这个工具是在GNU coreutils 8.15(2012年)中引入的,所以它很新. (4认同)
  • 如果传递的文件名不存在,则不起作用. (3认同)
  • @Purplejacket High Sierra 没有,甚至 v10.13.6。所以一定是因为莫哈韦沙漠。 (2认同)

Pau*_*ce. 301

尝试readlink解决符号链接:

readlink -e /foo/bar/baz
Run Code Online (Sandbox Code Playgroud)

  • 我宁愿使用'-f'而不是'-e',以便我们可以看到不存在的文件的绝对路径. (47认同)
  • 在我看来,`-m`是最好的选择. (13认同)
  • @iconoclast这些选项在OSX上不可用,并且根据BSD"readlink"联机帮助页:`只打印符号链接的目标.如果给定的参数不是符号链接,readlink将不打印任何内容并退出并显示错误`,因此readlink在OSX上不能用于此目的 (11认同)
  • 这看起来对我来说最简单,同时也是便携式的.readlink是gnu coreutils的端口,因此它几乎可以安装在任何Linux发行版上,除了一些嵌入式发行版. (5认同)
  • @Dalin:小牛队上的`/usr/bin/readlink`。或者您的意思是 OS X 上找不到这些选项?这似乎是一个发育不良的 BSD 版本...:p (2认同)
  • hluk:`-f` 选项也是在 OpenBSD 中使用的选项 (2认同)

dog*_*ane 240

#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
Run Code Online (Sandbox Code Playgroud)

  • 到目前为止唯一的POSIX解决方案不需要您编写和编译可执行文件,因为readlink和realpath不是POSIX (29认同)
  • 我使用`function realpath {echo $(cd $(dirname $ 1); pwd)/ $(basename $ 1); 在OS X上让自己成为一个`realpath`命令(目前接受的答案).谢谢! (21认同)
  • 不要忘记引用所有的东西.如果你不明白为什么,试试你的程序文件`ab`(a和b之间的两个空格,SO吃其中一个). (7认同)

pet*_*erh 78

忘掉readlinkrealpath可能会或可能不会被你的系统上安装.

在这里扩展了dogbane的答案,它被表达为一个函数:

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

myabsfile=$(get_abs_filename "../../foo/bar/file.txt")
Run Code Online (Sandbox Code Playgroud)

它是如何以及为什么有效?

该解决方案利用了这样一个事实:pwd当没有参数调用时,Bash内置命令将打印当前目录的绝对路径.

为什么我喜欢这个解决方案?

它是便携式的,不需要也不readlinkrealpath经常不上的默认安装中存在一个给定的Linux/Unix发行版.

如果dir不存在怎么办?

如上所述,如果给定的目录路径不存在,函数将失败并在stderr上打印.这可能不是你想要的.您可以扩展该功能以处理这种情况:

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  if [ -d "$(dirname "$1")" ]; then
    echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
  fi
}
Run Code Online (Sandbox Code Playgroud)

现在,如果父目录不存在,它将返回一个空字符串.

你如何处理尾随'..'或'.' 输入?

嗯,在这种情况下确实给出了绝对路径,但不是最小路径.它看起来像:

/Users/bob/Documents/..
Run Code Online (Sandbox Code Playgroud)

如果你想解决'..',你需要使脚本像:

get_abs_filename() {
  # $1 : relative filename
  filename=$1
  parentdir=$(dirname "${filename}")

  if [ -d "${filename}" ]; then
      echo "$(cd "${filename}" && pwd)"
  elif [ -d "${parentdir}" ]; then
    echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")"
  fi
}
Run Code Online (Sandbox Code Playgroud)

  • 我想补充一点,`realpath`来自coreutils包,它还包含诸如`who`,`touch`或`cat`等工具.它是相当标准的GNU工具集,所以你可以肯定它几乎安装在任何基于Linux的机器上.那么说,你是对的:它有2个问题:i)你可能会错过它在默认安装上非GNU unix系统(如OpenBSD)ii)这个工具是在8.15版本中引入的(所以从2012年开始它是相当新的),所以你会在长期稳定的系统(如RHEL 6)上错过它. (3认同)
  • @marbu realpath不存在于Ubuntu 14.04或Debian Wheezy上.随着时间的推移它可能会变得有些标准,但现在肯定不是.另请注意,OP没有提及有关linux或GNU的任何内容.Bash比这更广泛地使用. (3认同)
  • @dhardy。不确定我理解你的评论。这里提出的解决方案中排除交互式环境使用的是什么?...顺便说一句,就像本页上提供的所有其他替代答案一样。 (2认同)

Fli*_*imm 75

$ readlink -m FILE
/path/to/FILE
Run Code Online (Sandbox Code Playgroud)

这比readlink -e FILEor好realpath,因为即使文件不存在也能正常工作.

  • @KennethHoste:小牛队不提供`-m`选项. (5认同)
  • 绝对不是在DEFAULT OSX安装中。 (2认同)

Ale*_*hek 64

这个绝对路径转换器shell函数的相对路径

  • 不需要实用程序(只是cdpwd)
  • 适用于目录和文件
  • 处理...
  • 处理dir或文件名中的空格
  • 要求文件或目录存在
  • 如果给定路径上不存在任何内容,则不返回任
  • 处理绝对路径作为输入(基本上通过它们)

码:

function abspath() {
    # generate absolute path from relative path
    # $1     : relative filename
    # return : absolute path
    if [ -d "$1" ]; then
        # dir
        (cd "$1"; pwd)
    elif [ -f "$1" ]; then
        # file
        if [[ $1 = /* ]]; then
            echo "$1"
        elif [[ $1 == */* ]]; then
            echo "$(cd "${1%/*}"; pwd)/${1##*/}"
        else
            echo "$(pwd)/$1"
        fi
    fi
}
Run Code Online (Sandbox Code Playgroud)

样品:

# assume inside /parent/cur
abspath file.txt        => /parent/cur/file.txt
abspath .               => /parent/cur
abspath ..              => /parent
abspath ../dir/file.txt => /parent/dir/file.txt
abspath ../dir/../dir   => /parent/dir          # anything cd can handle
abspath doesnotexist    =>                      # empty result if file/dir does not exist
abspath /file.txt       => /file.txt            # handle absolute path input
Run Code Online (Sandbox Code Playgroud)

注意:这是基于nolan6000bsingh的答案,但修复了文件大小写.

我也理解原始问题是关于现有的命令行实用程序.但是因为这似乎是stackoverflow的问题,包括想要具有最小依赖性的shell脚本,我把这个脚本解决方案放在这里,所以我可以在以后找到它:)


les*_*eal 23

find命令可能有所帮助

find $PWD -name ex*
find $PWD -name example.log
Run Code Online (Sandbox Code Playgroud)

列出当前目录中或下面的所有文件,其名称与模式匹配.如果您只获得一些结果(例如,包含少量文件的树底部附近的目录),您可以简化它

find $PWD
Run Code Online (Sandbox Code Playgroud)

我在Solaris 10上使用它,它没有提到的其他实用程序.

  • 如果你依赖`PWD`,你可以简单地使用`$ PWD/$ filename`. (4认同)

hlu*_*luk 15

如果你没有readlink或realpath实用程序,你可以使用在bash和zsh中工作的以下函数(不确定其余部分).

abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }
Run Code Online (Sandbox Code Playgroud)

这也适用于不存在的文件(与python函数一样os.path.abspath).

不幸的abspath ./../somefile是没有摆脱点.


wjv*_*wjv 9

这是一个zsh-only函数,我喜欢它的紧凑性.它使用'A'扩展修饰符 - 参见zshexpn(1).

realpath() { for f in "$@"; do echo ${f}(:A); done }
Run Code Online (Sandbox Code Playgroud)

  • 哇,这是一个优雅的解决方案! (2认同)

bab*_*bou 7

一般没有这样的事情 absolute path一个文件(这个声明意味着,可能有一个以上的一般,因此使用了定冠词是不恰当的).An absolute path是从根"/"开始的任何路径,并且指定一个没有歧义的文件,独立于工作目录.(例如参见维基百科).

A relative path是从另一个目录开始解释的路径.它可能是工作目录,如果它是relative path由应用程序操纵(虽然不一定).当它在目录中的符号链接中时,通常旨在相对于该目录(尽管用户可能还有其他用途).

因此,绝对路径只是相对于根目录的路径.

路径(绝对路径或相对路径)可能包含也可能不包含符号链接.如果不是这样,它在某种程度上也不受链接结构变化的影响,但这不是必需的,甚至不是必需的.有人叫canonical path(或canonical file nameresolved path)的absolute path其中所有符号链接都得到了解决,即通过向whetever它们链接到的路径已被替换.命令realpathreadlink两者都寻找规范路径,但只有realpath一个选项来获取绝对路径而不必费心解析符号链接(以及其他几个选项来获取各种路径,绝对或相对于某个目录).

这需要几个评论:

  1. 如果已经创建了它们应该链接到的任何内容,则只能解析符号链接,这显然并非总是如此.命令realpathreadlink有选项来解释它.
  2. 路径上的目录以后可以成为符号链接,这意味着路径不再存在canonical.因此,概念是时间(或环境)依赖.
  3. 即使在理想情况下,当所有符号链接都可以解析时,canonical path文件可能仍然不止一个,原因有两个:
    • 包含该文件的分区可能已同时(ro)挂载在几个挂载点上.
    • 可能存在到文件的硬链接,这意味着该文件基本上存在于几个不同的目录中.

因此,即使有更严格的定义canonical path,也可能存在一些文件的规范路径.这也意味着限定符canonical有些不足,因为它通常意味着唯一性的概念.

这扩展了对该主题的简短讨论,以回答Bash中的另一个类似问题:检索给定相对的绝对路径

我的结论是,realpath设计更好,更灵活readlink.如果没有选项返回符号链接的值readlink,则不会使用它的唯一用途realpath.

  • 1-问题一直有效答案的事实并不意味着问题已经结束.这些问题不仅限于个人使用.实际上,有回复的徽章收集的票数超过了经过验证的答案.使用新工具,"最佳"答案可能会随着时间而改变.许多人使用通过网络搜索访问的旧答案. (5认同)

Arj*_*Arj 7

如果您只想使用内置函数,最简单的方法可能是:

find `pwd` -name fileName
Run Code Online (Sandbox Code Playgroud)

只需输入两个额外的单词,这将适用于所有 unix 系统以及 OSX。


Eug*_*kov 6

dogbane 回答什么是对未来的描述:

#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
Run Code Online (Sandbox Code Playgroud)

解释:

  1. 此脚本获取相对路径作为参数 "$1"
  2. 然后我们获得该路径的dirname部分(您可以将 dir 或 file 传递给该脚本):dirname "$1"
  3. 然后我们cd "$(dirname "$1")进入这个相对目录并通过运行pwdshell 命令获取它的绝对路径
  4. 之后,我们将basename附加到绝对路径:$(basename "$1")
  5. 作为最后一步,我们echo


Mar*_* An 6

在某些情况下,此问题的最佳答案可能会产生误导。想象一下,您要查找其绝对路径的文件位于$PATH变量中:

# node is in $PATH variable
type -P node
# /home/user/.asdf/shims/node
cd /tmp
touch node  # But because there is a file with the same name inside the current dir check out what happens below
readlink -e node
# /tmp/node
readlink -m node
# /tmp/node
readlink -f node
# /tmp/node
echo "$(cd "$(dirname "node")"; pwd -P)/$(basename "node")"
# /tmp/node
realpath node
# /tmp/node
realpath -e node
# /tmp/node

# Now let's say that for some reason node does not exist in current directory
rm node
readlink -e node
# <nothing printed>
readlink -m node    
# /tmp/node         # Note: /tmp/node does not exist, but is printed
readlink -f node
# /tmp/node         # Note: /tmp/node does not exist, but is printed
echo "$(cd "$(dirname "node")"; pwd -P)/$(basename "node")"
# /tmp/node         # Note: /tmp/node does not exist, but is printed
realpath node
# /tmp/node         # Note: /tmp/node does not exist, but is printed
realpath -e node
# realpath: node: No such file or directory
Run Code Online (Sandbox Code Playgroud)

基于以上内容,我可以得出结论:realpath -ereadlink -e可用于查找我们期望存在于当前目录中的文件的绝对路径,而结果不受$PATH变量的影响。唯一的区别是realpath输出到 stderr,但如果找不到文件,两者都会返回错误代码:

cd /tmp
rm node
realpath -e node ; echo $?
# realpath: node: No such file or directory
# 1
readlink -e node ; echo $?
# 1
Run Code Online (Sandbox Code Playgroud)

现在,如果您想要中存在的文件的绝对路径 a$PATH,则以下命令将是合适的,与当前目录中是否存在同名文件无关。

type -P example.txt
# /path/to/example.txt

# Or if you want to follow links
readlink -e $(type -P example.txt)
# /originalpath/to/example.txt

# If the file you are looking for is an executable (and wrap again through `readlink -e` for following links )
which executablefile
# /opt/bin/executablefile

Run Code Online (Sandbox Code Playgroud)

如果缺少,则回退$PATH,例如:

cd /tmp
touch node
echo $(readlink -e node || type -P node)
# /tmp/node
rm node
echo $(readlink -e node || type -P node)
# /home/user/.asdf/shims/node
Run Code Online (Sandbox Code Playgroud)


Zor*_*ayr 5

用 Homebrew 回答

realpath是最好的答案,但如果您没有安装它,您必须首先运行brew install coreutils它将安装具有许多很棒功能的coreutils 。编写自定义函数并导出它的工作量太大,而且对于这样的事情存在出错的风险,这里有两行:

$ brew install coreutils
$ realpath your-file-name.json 
Run Code Online (Sandbox Code Playgroud)