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

南楼画角 提交于 2020-02-27 04:18:19

问题:是否有一个简单的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)

#1楼

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

realpath() { for f in "$@"; do echo ${f}(:A); done }

#2楼

$ readlink -m FILE
/path/to/FILE

这比readlink -e FILErealpath更好,因为即使文件不存在也可以工作。


#3楼

一般有作为没有这样的事情absolute path到一个文件中(这个声明意味着,可能有一个以上的一般,因此使用了定冠词the是不恰当的)。 absolute path是从根目录“ /”开始并指定文件的任何路径,而与工作目录无关(例如,参见Wikipedia )。

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

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

路径(绝对路径或相对路径)可能包含也可能不包含符号链接。 如果不是这样,则在某种程度上也不能改变链接结构,但这不是必须的,甚至是不希望的。 有人将canonical path (或canonical file name或已resolved path )称为absolute path ,其中所有符号链接均已解析,即已被链接到的符号路径所替代。 命令realpathreadlink都在寻找规范的路径,但是只有realpath可以选择获取绝对路径而不必费解解析符号链接(以及其他几种选择来获取各种路径,无论是绝对路径还是相对于某个目录)。

这需要一些说明:

  1. 仅当已经创建了符号链接时,才可以解析符号链接,这显然并非总是如此。 命令realpathreadlink具有解决方案。
  2. 路径上的目录以后可以变成符号链接,这意味着该路径不再canonical 。 因此,该概念取决于时间(或环境)。
  3. 即使在理想情况下,当所有符号链接都可以解析时,文件的canonical path仍然可能不止一个,原因有两个:
    • 包含文件的分区可能已同时( ro )安装在几个安装点上。
    • 可能存在指向该文件的硬链接,这实际上意味着该文件存在于几个不同的目录中。

因此,即使对canonical path定义要严格得多,文件也可能有多个规范路径。 这也意味着限定词的canonical性不足,因为它通常暗示唯一性的概念。

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

我的结论是,与readlink相比, realpath的设计更好,更灵活。 readlink唯一未包含在realpath中的用途是不带选项返回符号链接值的调用。


#4楼

忘记可能已安装或未安装在系统上的readlinkrealpath

在这里扩展狗狗的答案 ,它表示为一个函数:

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

然后可以像这样使用它:

myabsfile=$(get_abs_filename "../../foo/bar/file.txt")

它如何以及为什么起作用?

该解决方案利用了以下事实:当不带参数调用时,Bash内置的pwd命令将打印当前目录的绝对路径。

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

它是可移植的,并且不需要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
}

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

您如何处理尾随的“ ..”或“。” 在输入?

好吧,在这种情况下,它确实提供了一条绝对的路径,但不是一条最小的路径。 它看起来像:

/Users/bob/Documents/..

如果要解析“ ..”,则需要使脚本类似:

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
}

#5楼

对于目录, dirname跳入../并返回./

可以修改nolan6000的功能以修复以下问题:

get_abs_filename() {
  # $1 : relative filename
  if [ -d "${1%/*}" ]; then
    echo "$(cd ${1%/*}; pwd)/${1##*/}"
  fi
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!