如何通过 Shell (BASH/ZSH/SH) 获取文件的绝对路径?

Posted

技术标签:

【中文标题】如何通过 Shell (BASH/ZSH/SH) 获取文件的绝对路径?【英文标题】:How to obtain the absolute path of a file via Shell (BASH/ZSH/SH)? 【发布时间】:2011-04-24 07:45:12 【问题描述】:

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

【问题讨论】:

我认为@DennisWilliamson 的答案(使用 -m 选项)对于(通常)更具可移植性和处理不存在的文件来说是优越的。 或者弗利姆的回答;两者都是很好的解决方案。然而,Bannier 最好地回答了 我的 原始问题。 OSX 用户:见this answer Bash: retrieve absolute path given relative的可能重复 【参考方案1】:

使用realpath

$ realpath example.txt
/home/username/example.txt

【讨论】:

+1,非常好的程序。但请注意,它是一个外部命令(不是内置的 shell),默认情况下可能不会出现在每个系统中,即您可能需要安装它。在 Debian 中,它位于一个单独的同名软件包中。 我在路径中添加了一个realpath,其中包括:github.com/westonruter/misc-cli-tools/blob/master/realpath @Dalin:尝试安装 coreutils。二进制文件名为 grealpath。 这个工具是在 GNU coreutils 8.15(2012 年)中引入的,所以它很新。 @WalterTross,可通过 Homebrew 的 coreutils 公式获得。【参考方案2】:

尝试readlink,它将解析符号链接:

readlink -e /foo/bar/baz

【讨论】:

我宁愿使用 '-f' 而不是 '-e' 这样我们就可以看到不存在文件的绝对路径。 这对我来说是最简单的,同时也是便携的。 readlink 是 gnu coreutils 的端口,所以它几乎可以安装在任何 linux 发行版上,除了一些嵌入式发行版。 在我看来-m 是最好的选择。 @Dalin: /usr/bin/readlink 在小牛队。还是您的意思是在 OS X 上找不到这些选项?这似乎是一个发育不良的 BSD 版本... :p @iconoclast 这些选项在 OSX 上不可用,并且根据 BSD readlink 手册页:only the target of the symbolic link is printed. If the given argument is not a symbolic link, readlink will print nothing and exit with an error,因此 readlink 在 OSX 上无法用于此目的【参考方案3】:
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"

【讨论】:

别忘了引用所有的东西。如果您不明白为什么,请在文件 a b 上尝试您的程序(a 和 b 之间有两个空格,所以会吃掉其中一个)。 也在“/”上试试这个,它变成了“///” 迄今为止唯一不需要您编写和编译可执行文件的 POSIX 解决方案,因为 readlink 和 realpath 不是 POSIX 我在 OS X 上使用function realpath echo $(cd $(dirname $1); pwd)/$(basename $1); 使自己成为realpath 命令(当前接受的答案)。谢谢! 我使用这种方法为脚本定义日志文件名:LOG=$(echo $(cd $(dirname $0); pwd)/$(basename $0 .sh).log)【参考方案4】:

忘记readlinkrealpath 可能会或可能不会安装在您的系统上。

在上面的dogbane的回答上展开,它被表示为一个函数:

#!/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 发行版的默认安装中通常不存在。

如果目录不存在怎么办?

如上所述,如果给定的目录路径不存在,该函数将失败并在 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

【讨论】:

@dhardy。不确定我是否理解您的评论。此处提出的解决方案中排除了交互式环境使用的内容是什么? ...顺便说一句,就像此页面上提供的所有其他替代答案一样。 我想补充一点,realpath 来自 coreutils 包,其中还包含whotouchcat 等工具。这是一套非常标准的 GNU 工具,因此您可以确定它几乎安装在任何基于 linux 的机器上。也就是说,您是对的:它有两个问题:i) 您可能会在默认安装时错过它非 GNU unix 系统(如 OpenBSD)ii)此工具是在 8.15 版中引入的(所以它是 2012 年以来的新功能),因此您会在长期稳定的系统(如 RHEL 6)上错过它。 好吧,至少 Continuum Analytics(Anaconda Python distribution 的制造商)似乎喜欢这个答案。它在他们的"activate" script 中实现(带有参考链接),用于激活由 conda 工具创建的虚拟环境。所以……好一个! 这只适用于目录(因为没有别的),不能处理“..”和“.”。请参阅我应该处理所有事情的答案:***.com/a/23002317/2709 @marbu realpath 在 Ubuntu 14.04 或 Debian Wheezy 上不存在。随着时间的推移,它可能会变得有些标准,但现在肯定不是。另请注意,OP 没有说任何关于 linux 或 GNU 的内容。 Bash 的使用范围比这更广泛。【参考方案5】:
$ readlink -m FILE
/path/to/FILE

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

【讨论】:

不错。这也适用于确实存在但不是符号链接的文件/目录。 我在 OS X 10.9 (Mavericks) 上确实有 readlink,所以这绝对是这里最好的答案。 @KennethHoste:-m 选项在 Mavericks 上不可用。 绝对不是默认的 OSX 安装。 适用于 linux (CentOS) 谢谢,因为它不存在 realpath【参考方案6】:

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

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

代码:

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

示例:

# 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

注意:这是基于from nolan6000 和bsingh 的答案,但修正了文件大小写。

我也明白最初的问题是关于现有的命令行实用程序。但由于这似乎是关于 *** 的问题,包括希望具有最小依赖关系的 shell 脚本,所以我把这个脚本解决方案放在这里,这样我以后可以找到它:)

【讨论】:

谢谢。这就是我在 OSX 上所使用的 这不适用于带有空格的目录,即:$ abspath 'a b c/file.txt' 那是因为cd 的参数没有被引用。为了克服这个问题,不要将整个参数引用到echo(这些引用有原因吗?)只引用路径参数。 IE。将echo "$(cd $1%/*; pwd)/$1##*/" 替换为echo $(cd "$1%/*"; pwd)/$1##*/ @george 感谢您的注意,我已修复它。 我查看了几十个半途而废的解决方案,这绝对是最简洁准确的 bash-only 解决方案。您可以通过将echo "$(cd "$1"; pwd)" 替换为(cd "$1"; pwd) 来进一步瘦身。这里不需要回显。 @Six True,已更新。大括号( ... ) 仍然需要,因此cd 发生在子shell 中,因为我们不想更改abspath 的任何调用者的工作目录。【参考方案7】:

find 命令可能会有所帮助

find $PWD -name ex*
find $PWD -name example.log

列出当前目录中或下方名称与模式匹配的所有文件。如果你只会得到几个结果(例如,靠近树底部的目录包含几个文件),你可以简化它,只是

find $PWD

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

【讨论】:

我在第一次阅读时并没有理解这个评论;这里的关键点是,如果您为 find 命令提供绝对路径,那么它将以绝对路径输出结果。所以使用 $PWD 是你所在位置的绝对路径,所以你得到的输出是绝对的。 如果你依赖PWD,你可以简单地使用$PWD/$filename 这种方法可以通过使用 -maxdepth 1 来改进。也不要忘记在这里引用 - 潜在的安全问题,这取决于你如何使用它。 @jonny: 如果 $filename 已经是绝对的,$PWD/$filename 会失败。 如果文件名被指定为“./filename.txt”(带有前导点和斜线),则会失败。【参考方案8】:

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

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

【讨论】:

哇,这是一个优雅的解决方案!【参考方案9】:

如果您没有 readlink 或 realpath 实用程序,则可以使用以下适用于 bash 和 zsh 的函数(不确定其余的)。

abspath ()  case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; 

这也适用于不存在的文件(python 函数 os.path.abspath 也是如此)。

很遗憾,abspath ./../somefile 没有消除这些点。

【讨论】:

对我来说看起来很便携。另一方面,例如在包含换行符的文件名上会中断。 若要进一步改进,请将echo "$1" 替换为printf "%s\n" "$1"(与第二个回显相同)。 echo 可能会在其参数中解释反斜杠。 再一次,你是对的!确实,zsh 中 echo 命令的行为与 bash 不同。 严格来说,在 POSIX 下,如果参数包含反斜杠,则 echo 的行为是未定义的。但是,它是在 XSI 扩展下定义的(即,echo 应该解释转义序列)。但是 bash 和 zsh 都离 POSIX 合规性还很远…… 对不起,我不明白这一点。我已经提供了一个脚本的答案,它具有更多功能,并且不需要在 shell 脚本中使用。【参考方案10】:

文件中一般没有theabsolute path这样的东西(这个陈述意味着一般可能有多个,因此使用定冠词the 不合适)。 absolute path 是从根“/”开始的任何路径,它指定了一个独立于工作目录的无歧义文件。(参见例如 wikipedia)。

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

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

路径(绝对或相对)可能包含也可能不包含符号链接。如果不是这样,它也有点不受链接结构变化的影响,但这不是必需的,甚至不是可取的。有些人将canonical path(或canonical file nameresolved path)称为absolute path,其中所有符号链接都已解决,即已被链接到的路径所取代。命令realpathreadlink 都查找规范路径,但只有realpath 可以选择获取绝对路径,而无需费心解析符号链接(以及获取各种路径的其他几个选项,绝对或相对于某个目录)。

这需要几点说明:

    符号链接只有在它们应该被解析的情况下才能被解析 链接到已经创建,显然并非总是如此。命令realpathreadlink 有解决这个问题的选项。 路径上的目录以后可以成为符号链接,这意味着路径不再是canonical。因此,这个概念取决于时间(或环境)。 即使在理想情况下,当所有符号链接都可以解析时, 一个文件中可能还有多个canonical path,对于两个 原因: 包含该文件的分区可能已同时 (ro) 安装在多个安装点上。 可能存在指向该文件的硬链接,这意味着该文件实际上存在于多个不同的目录中。

因此,即使canonical path 的定义更加严格,文件也可能有多个规范路径。这也意味着限定词 canonical 有点不够用,因为它通常意味着唯一性的概念。

这扩展了对该主题的简短讨论,以回答Bash: retrieve absolute path given relative的另一个类似问题

我的结论是realpathreadlink 设计得更好,更灵活。 realpath 未涵盖的 readlink 的唯一用途是调用没有返回符号链接值的选项。

【讨论】:

我不介意被否决,但我想了解为什么这样我就可以学到一些东西,无论是技术上的,还是关于网站上被认为是正确做法的东西。嗯...至少它促使我注册Meta Stack Overflow 以更好地了解当地社会学。我推荐它。 -- 不过,如果有人对我的回答不恰当有意见,我很感兴趣。 (a) 该问题有 2+1/2 年前的有效答案,(b) 有一个(单一)绝对路径对应于 相对路径 (这就是我想要的),虽然可能不是你指出的文件。顺便说一句,关于 realpathreadlink 甚至符号链接的任何 cmets 都超出了我的要求。 第二条评论:简短的回答通常比长篇大论更有用。堆栈溢出通常用于提出具体问题。 1- 一个问题得到有效答案的时间有多长并不意味着它已关闭。这些问题并非仅供个人使用。确实,回复的徽章收集的选票比经过验证的答案多。使用新工具,“最佳”答案可能会随着时间而改变。许多人使用通过网络搜索获得的旧答案。 2 - 你坚持有一个(单一的)绝对路径对应于一个相对路径。虽然我猜你所说的“对应”是什么意思,即通过一组给定的转换从原始路径派生的路径,但你的陈述仍然不正确。有一个独特的“对应”规范路径。 canonical 这个词正是指这种相对于一组转换的唯一性。但是,例如,/dev/cdrom 是一个非常好的绝对路径,即使它实际上是到 /dev/sr0 的链接。两者都指向同一个设备。我最初的回答指向了一篇相关的网络文章。【参考方案11】:

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

find `pwd` -name fileName

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

【讨论】:

我会在-name 之前添加-maxdepth 1(假设文件在当前目录中)。没有它,它将适用于 pwd 的任何子目录中的文件,但不适用于其他文件。 确实你是对的,问题确实指定该文件将在当前目录中。 “但不与他人在一起”是什么意思? 我的意思是find 不会在pwd 下的目录树之外找到文件。例如,如果你尝试find . -name ../existingFile,它会失败。 很公平,是的,这假设您想要在您的 cwd(根据原始问题)或 cwd 树中的任何位置(不是原始问题)中打印文件的完整路径.【参考方案12】:

dogbaneanswer 以及即将发生的事情的描述:

#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"

解释:

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

【讨论】:

【参考方案13】:

用 Homebrew 回答

realpath 是最好的答案,但如果你没有安装它,你必须先运行brew install coreutils,它将安装coreutils 并提供许多很棒的功能。编写一个自定义函数并导出它是太多的工作和错误的风险,这里有两行:

$ brew install coreutils
$ realpath your-file-name.json 

【讨论】:

realpath 解析符号链接【参考方案14】:

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

# node is in $PATH variable
type -P node
# /home/user/.asdf/shims/node
cd /tmp
touch node
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

基于以上我可以得出结论: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

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

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

还有一个,如果丢失则回退到$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

【讨论】:

【参考方案15】:

对于目录dirname../ 触发并返回./

nolan6000's function 可以修改来解决这个问题:

get_abs_filename() 
  # $1 : relative filename
  if [ -d "$1%/*" ]; then
    echo "$(cd $1%/*; pwd)/$1##*/"
  fi

【讨论】:

欢迎来到 SO!对于小的更改和备注,在现有答案中添加评论可能比添加答案更合适,特别是如果这个复制的答案缺少原始答案的许多其他信息。一旦你收集了更多的声望,你就可以将 cmets 添加到其他人的答案中。现在,请尝试通过提出独特的、有价值的问题或提供独立的、好的答案来收集声誉。 由于您指的是 nolan6000 的回答,请注意发帖者 dhardy 已经评论说他不会接受 nolan6000 的回答,因为他不是在寻找脚本。所以严格来说,你的回答并不能回答问题。 该函数可以添加到.profile,因此可以交互使用。 如果$1 是一个普通的文件名,这将不起作用:get_abs_filename foo -> 什么都没有(或者&lt;current_dir&gt;/foo/foo 如果foo 是一个目录)。【参考方案16】:

这不是问题的答案,而是针对那些编写脚本的人:

echo `cd "$1" 2>/dev/null&&pwd||(cd "$(dirname "$1")";pwd|sed "s|/*\$|/$1##*/|")`

它可以正确处理 / .. ./ 等。我似乎也在 OSX 上工作

【讨论】:

【参考方案17】:

我在我的系统上放置了以下脚本,当我想快速获取当前目录中文件的完整路径时,我将其称为 bash 别名:

#!/bin/bash
/usr/bin/find "$PWD" -maxdepth 1 -mindepth 1 -name "$1"

我不知道为什么,但是在 OS X 上,当被脚本调用时,“$PWD”会扩展为绝对路径。在命令行上调用 find 命令时,它不会。但它可以满足我的需求……享受。

【讨论】:

$PWD 始终具有工作目录的绝对路径。此外,find 不会容忍斜线,因此您没有按要求回答问题。一个更快的方法来做你想做的事情就是echo "$PWD/$1"【参考方案18】:
#! /bin/bash

file="$@"
realpath "$file" 2>/dev/null || eval realpath $(echo $file | sed 's/ /\\ /g')

这弥补了realpath的不足,将其存储在一个shell脚本fullpath中。您现在可以调用:

$ cd && touch a\ a && rm A 2>/dev/null 
$ fullpath "a a"
/home/user/a a
$ fullpath ~/a\ a
/home/user/a a
$ fullpath A
A: No such file or directory.

【讨论】:

它解决了什么问题? realpath "foo bar" -> /home/myname/foo bar 。如果您懒得引用命令行参数,那不是realpath 的错。 同意,它更像是一个方便的包装器。【参考方案19】:

Ruby 中获取绝对路径的替代方法:

realpath() ruby -e "require 'Pathname'; puts Pathname.new('$1').realpath.to_s";

使用无参数(当前文件夹)和相对和绝对文件或文件夹路径作为参数。

【讨论】:

【参考方案20】:

如果您的脚本可能坚持存在 bash 或 bash 兼容的 shell,则 Alexander Klimetschek 的回答是可以的。它不适用于仅符合 POSIX 的 shell。

此外,当最终文件是根目录下的文件时,输出将是//file,这在技术上并非不正确(双 / 被系统视为单个文件)但看起来很奇怪。

这是一个适用于所有符合 POSIX 标准的 shell 的版本,它使用的所有外部工具也是 POSIX 标准所要求的,并且它明确处理根文件的情况:

#!/bin/sh

abspath ( ) 
    if [ ! -e "$1" ]; then
        return 1
    fi

    file=""
    dir="$1"
    if [ ! -d "$dir" ]; then
        file=$(basename "$dir")
        dir=$(dirname "$dir")
    fi

    case "$dir" in
        /*) ;;
        *) dir="$(pwd)/$dir"
    esac
    result=$(cd "$dir" && pwd)

    if [ -n "$file" ]; then
        case "$result" in
            */) ;;
             *) result="$result/"
        esac
        result="$result$file"
    fi

    printf "%s\n" "$result"


abspath "$1"

将其放入文件并使其可执行,您就有了一个 CLI 工具来快速获取文件和目录的绝对路径。或者只是复制该函数并在您自己的符合 POSIX 的脚本中使用它。它将相对路径转换为绝对路径并按原样返回绝对路径。

有趣的修改:

如果将result=$(cd "$dir" &amp;&amp; pwd) 行替换为result=$(cd "$dir" &amp;&amp; pwd -P),则最终文件路径中的所有符号链接也会被解析。

如果对第一次修改不感兴趣,可以提前返回优化绝对案例:

abspath ( ) 
    if [ ! -e "$1" ]; then
        return 1
    fi

    case "$1" in
        /*)
            printf "%s\n" "$1"
            return 0
    esac

    file=""
    dir="$1"
    if [ ! -d "$dir" ]; then
        file=$(basename "$dir")
        dir=$(dirname "$dir")
    fi

    result=$(cd "$dir" && pwd)

    if [ -n "$file" ]; then
        case "$result" in
            */) ;;
            *) result="$result/"
        esac
        result="$result$file"
    fi

    printf "%s\n" "$result"

既然会出现问题:为什么是printf 而不是echo

echo 主要用于将用户的消息打印到标准输出。脚本编写者所依赖的许多echo 行为实际上是未指定的。即使是著名的-n 也不是标准化的,也不是\t 用于制表符。 POSIX 标准说:

要写入标准输出的字符串。如果第一个操作数是 -n,或者任何操作数包含字符,则结果由实现定义 - https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html

因此,每当您想向标准输出写入内容并且不是为了向用户打印消息时,建议使用printf,因为printf 的行为已完全定义。我的函数使用 stdout 传递结果,这不是给用户的消息,因此仅使用 printf 保证完美的可移植性。

【讨论】:

【参考方案21】:

我用单行

(cd $FILENAME%/*; pwd)

但是,这只能在$FILENAME 具有实际存在的任何类型(相对或绝对)的前导路径时使用。如果根本没有引导路径,那么答案就是$PWD。如果前导路径不存在,则答案可能是不确定的,否则,如果路径是绝对路径,则答案只是$FILENAME%/*

将所有这些放在一起,我建议使用以下函数

function abspath() 
  # argument 1: file pathname (relative or absolute)
  # returns: file pathname (absolute)
  if [ "$1" == "$1##*/" ]; then # no path at all
    echo "$PWD"
  elif [ "$1:0:1" == "/" -a "$1/../" == "$1" ]; then # strictly absolute path
    echo "$1%/*"
  else # relative path (may fail if a needed folder is non-existent)
    echo "$(cd $1%/*; pwd)"
  fi

另请注意,这仅适用于 bash 和兼容的 shell。我不相信替换在简单的 shell sh 中起作用。

【讨论】:

【参考方案22】:

大家好,我知道这是一个旧线程,但我只是将其发布以供其他像我一样访问过此的人参考。如果我正确理解了这个问题,我认为是locate $filename 命令。它显示提供的文件的绝对路径,但前提是它存在。

【讨论】:

locate 是一个按名称搜索文件/路径的实用程序。它可能会完成这项工作,但也可能会找到其他匹配项,并且如果不首先以 root 身份调用 updatedb 就可能找不到现有文件。

以上是关于如何通过 Shell (BASH/ZSH/SH) 获取文件的绝对路径?的主要内容,如果未能解决你的问题,请参考以下文章

Linux基础知识

1.1.2 linux入门和基本操作使用

如何检测我的 shell 脚本是不是通过管道运行?

Emacs Shell模式:如何让TAB字符通过?

通过 SSH 运行 shell 时如何自动输入?

如何通过 docker run 将参数传递给 Shell 脚本