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

发布于 2024-09-27 06:41:54 字数 809 浏览 2 评论 0 原文

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

用例:我位于目录 /a/b 中,我想在命令行上打印文件 c 的完整路径,以便我可以轻松粘贴它进入另一个程序:/a/b/c。在处理长路径时,简单但一个小程序可以为我节省 5 秒左右的时间,最终加起来。因此,令我惊讶的是,我找不到一个标准实用程序来执行此操作 - 真的没有吗?

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

#!/usr/bin/python
# Author: Diggory Hardy <[email protected]>
# 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)

Question: is there a simple sh/bash/zsh/fish/... command to print the absolute path of whichever file I feed it?

Usage case: I'm in directory /a/b and I'd like to print the full path to file c on the command-line so that I can easily paste it into another program: /a/b/c. Simple, yet a little program to do this could probably save me 5 or so seconds when it comes to handling long paths, which in the end adds up. So it surprises me that I can't find a standard utility to do this — is there really none?

Here's a sample implementation, abspath.py:

#!/usr/bin/python
# Author: Diggory Hardy <[email protected]>
# 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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(24

恋你朝朝暮暮 2024-10-04 06:41:54

使用 realpath

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

Use realpath

$ realpath example.txt
/home/username/example.txt
少女净妖师 2024-10-04 06:41:54

尝试 readlink 这将解析符号链接:

readlink -e /foo/bar/baz

Try readlink which will resolve symbolic links:

readlink -e /foo/bar/baz
埋情葬爱 2024-10-04 06:41:54
#! /bin/sh
echo "$(cd "$(dirname -- "$1")" >/dev/null; pwd -P)/$(basename -- "$1")"
#! /bin/sh
echo "$(cd "$(dirname -- "$1")" >/dev/null; pwd -P)/$(basename -- "$1")"
蹲墙角沉默 2024-10-04 06:41:54

忘记您的系统上可能安装或未安装的 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 发行版的默认安装中通常不存在这些。

如果 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
}

Forget about readlink and realpath which may or may not be installed on your system.

Expanding on dogbane's answer above here it is expressed as a function:

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

you can then use it like this:

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

How and why does it work?

The solution exploits the fact that the Bash built-in pwd command will print the absolute path of the current directory when invoked without arguments.

Why do I like this solution ?

It is portable and doesn't require neither readlink or realpath which often does not exist on a default install of a given Linux/Unix distro.

What if dir doesn't exist?

As given above the function will fail and print on stderr if the directory path given does not exist. This may not be what you want. You can expand the function to handle that situation:

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

Now it will return an empty string if one the parent dirs do not exist.

How do you handle trailing '..' or '.' in input ?

Well, it does give an absolute path in that case, but not a minimal one. It will look like:

/Users/bob/Documents/..

If you want to resolve the '..' you will need to make the script like:

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
}
别想她 2024-10-04 06:41:54
$ readlink -m FILE
/path/to/FILE

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

$ readlink -m FILE
/path/to/FILE

This is better than readlink -e FILE or realpath, because it works even if the file doesn't exist.

独享拥抱 2024-10-04 06:41:54

这种相对路径到绝对路径转换器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
}

示例:

# 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

< em>注意:这是基于 nolan6000bsingh,但修复了文件大小写。

我也了解最初的问题是关于现有的命令行实用程序。但由于这似乎是 stackoverflow 上的问题,其中包括希望具有最小依赖关系的 shell 脚本,因此我将此脚本解决方案放在这里,以便稍后可以找到它:)

This relative path to absolute path converter shell function

  • requires no utilities (just cd and pwd)
  • works for directories and files
  • handles .. and .
  • handles spaces in dir or filenames
  • requires that file or directory exists
  • returns nothing if nothing exists at the given path
  • handles absolute paths as input (passes them through essentially)

Code:

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
}

Sample:

# 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

Note: This is based on the answers from nolan6000 and bsingh, but fixes the file case.

I also understand that the original question was about an existing command line utility. But since this seems to be THE question on stackoverflow for that including shell scripts that want to have minimal dependencies, I put this script solution here, so I can find it later :)

も星光 2024-10-04 06:41:54

find 命令可能会帮助

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

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

find $PWD

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

The find command may help

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

Lists all the files in or below the current directory with names matching the pattern. You can simplify it if you will only get a few results (e.g. directory near bottom of tree containing few files), just

find $PWD

I use this on Solaris 10, which doesn't have the other utilities mentioned.

月亮邮递员 2024-10-04 06:41:54

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

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

Here's a zsh-only function that I like for its compactness. It uses the ‘A’ expansion modifier — see zshexpn(1).

realpath() { for f in "$@"; do echo ${f}(:A); done }
素衣风尘叹 2024-10-04 06:41:54

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

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

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

不幸的是 abspath ./../somefile 并没有去掉这些点。

If you don't have readlink or realpath utilities than you can use following function which works in bash and zsh (not sure about the rest).

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

This also works for nonexistent files (as does the python function os.path.abspath).

Unfortunately abspath ./../somefile doesn't get rid of the dots.

稳稳的幸福 2024-10-04 06:41:54

通常不存在文件的绝对路径(这一说法意味着一般情况下可能有多个,因此使用定冠词 > 是不合适的)。 绝对路径是从根“/”开始的任何路径,并指定一个独立于工作目录而没有歧义的文件。(参见示例维基百科)。

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

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

路径(绝对或相对)可能包含也可能不包含符号链接。如果不这样做,则它在某种程度上也不受链接结构变化的影响,但这不一定是必需的,甚至不是所希望的。有些人将规范路径(或规范文件名解析路径)称为绝对路径,其中所有符号链接已解决,即已被替换为它们链接到的路径。命令 realpathreadlink 都查找规范路径,但只有 realpath 可以选择获取绝对路径,而无需费心解析符号链接(以及其他几个选项来获取各种类型的路径,绝对路径或相对于某个目录的路径)。

这需要注意几点:

  1. 符号链接只有在它们应该被解析的情况下才能被解析
    链接已创建,显然情况并非总是如此。命令 realpathreadlink 有选项来解决这个问题。
  2. 路径上的目录稍后可以成为符号链接,这意味着该路径不再规范。因此,这个概念是依赖于时间(或环境)的。
  3. 即使在理想情况下,当所有符号链接都可以解析时,
    一个文件可能仍然有多个规范路径,对于两个
    原因:

    • 包含该文件的分区可能已同时挂载 (ro) 到多个挂载点上。
    • 该文件可能存在硬链接,这意味着该文件本质上存在于多个不同的目录中。

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

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

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

There is generally no such thing as the absolute path to a file (this statement means that there may be more than one in general, hence the use of the definite article the is not appropriate). An absolute path is any path that start from the root "/" and designates a file without ambiguity independently of the working directory.(see for example wikipedia).

A relative path is a path that is to be interpreted starting from another directory. It may be the working directory if it is a relative path being manipulated by an application
(though not necessarily). When it is in a symbolic link in a directory, it is generally intended to be relative to that directory (though the user may have other uses in mind).

Hence an absolute path is just a path relative to the root directory.

A path (absolute or relative) may or may not contain symbolic links. If it does not, it is also somewhat impervious to changes in the linking structure, but this is not necessarily required or even desirable. Some people call canonical path ( or canonical file name or resolved path) an absolute path in which all symbolic links have been resolved, i.e. have been replaced by a path to whetever they link to. The commands realpath and readlink both look for a canonical path, but only realpath has an option for getting an absolute path without bothering to resolve symbolic links (along with several other options to get various kind of paths, absolute or relative to some directory).

This calls for several remarks:

  1. symbolic links can only be resolved if whatever they are supposed to
    link to is already created, which is obviously not always the case. The commands realpath and readlink have options to account for that.
  2. a directory on a path can later become a symbolic link, which means that the path is no longer canonical. Hence the concept is time (or environment) dependent.
  3. even in the ideal case, when all symbolic links can be resolved,
    there may still be more than one canonical path to a file, for two
    reasons:

    • the partition containing the file may have been mounted simultaneously (ro) on several mount points.
    • there may be hard links to the file, meaning essentially the the file exists in several different directories.

Hence, even with the much more restrictive definition of canonical path, there may be several canonical paths to a file. This also means that the qualifier canonical is somewhat inadequate since it usually implies a notion of uniqueness.

This expands a brief discussion of the topic in an answer to another similar question at Bash: retrieve absolute path given relative

My conclusion is that realpath is better designed and much more flexible than readlink.
The only use of readlink that is not covered by realpath is the call without option returning the value of a symbolic link.

小鸟爱天空丶 2024-10-04 06:41:54

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

find `pwd` -name fileName

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

The simplest if you want to use only builtins is probably:

find `pwd` -name fileName

Only an extra two words to type, and this will work on all unix systems, as well as OSX.

起风了 2024-10-04 06:41:54

dogbane answer 并描述了即将发生的情况:

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

说明:

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

The dogbane answer with the description what is coming on:

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

Explanation:

  1. This script get relative path as argument "$1"
  2. Then we get dirname part of that path (you can pass either dir or file to this script): dirname "$1"
  3. Then we cd "$(dirname "$1") into this relative dir and get absolute path for it by running pwd shell command
  4. After that we append basename to absolute path: $(basename "$1")
  5. As final step we echo it
佞臣 2024-10-04 06:41:54

使用 Homebrew

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

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

Answer with Homebrew

realpath is the best answer, but if you don't have it installed, you must first run brew install coreutils which will install coreutils with lots of awesome functions. Writing a custom function and exporting it is too much work and risk for error for something like this, here are two lines:

$ brew install coreutils
$ realpath your-file-name.json 
违心° 2024-10-04 06:41:54

在某些情况下,此问题的最佳答案可能会产生误导。想象一下,您要查找其绝对路径的文件位于 $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

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

cd /tmp
rm node
realpath -e node ; echo $?
# realpath: node: No such file or directory
# 1
readlink -e node ; echo $?
# 1

现在,如果您想要 中存在的文件的绝对路径 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

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

The top answers in this question may be misleading in some cases. Imagine that the file, whose absolute path you want to find, is in the $PATH variable:

# 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

Based on the above I can conclude that: realpath -e and readlink -e can be used for finding the absolute path of a file, that we expect to exist in current directory, without result being affected by the $PATH variable. The only difference is that realpath outputs to stderr, but both will return error code if file is not found:

cd /tmp
rm node
realpath -e node ; echo $?
# realpath: node: No such file or directory
# 1
readlink -e node ; echo $?
# 1

Now in case you want the absolute path a of a file that exists in $PATH, the following command would be suitable, independently on whether a file with same name exists in current dir.

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

And a, fallback to $PATH if missing, example:

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
溺ぐ爱和你が 2024-10-04 06:41:54

在 zsh 中,是的。

假设您的路径存储在变量中,您可以使用 :P 修饰符来获取文件的绝对路径。

示例:

f='../example.txt'
echo ${f:P}

上面将打印 ../example.txt 的绝对路径。

您也可以使用 :A 修饰符来进一步解析符号链接,但这取决于安装的 realpath

f='../example.txt'
echo ${f:A}

请参阅 https://zsh.sourceforge.io/Doc/Release/Expansion.html #修饰符

In zsh, yes there is.

Assuming your path is stored in a variable, you can use the :P modifier to get the absolute path of the file.

Example:

f='../example.txt'
echo ${f:P}

The above will print the absolute path of ../example.txt.

You can alternatively use the :A modifier to further resolve symbolic links, but this depends on realpath being installed.

f='../example.txt'
echo ${f:A}

See https://zsh.sourceforge.io/Doc/Release/Expansion.html#Modifiers

不离久伴 2024-10-04 06:41:54

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

nolan6000 的函数可以修改来解决这个问题:

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

For directories dirname gets tripped for ../ and returns ./.

nolan6000's function can be modified to fix that:

get_abs_filename() {
  # $1 : relative filename
  if [ -d "${1%/*}" ]; then
    echo "$(cd ${1%/*}; pwd)/${1##*/}"
  fi
}
极度宠爱 2024-10-04 06:41:54

这不是问题的答案,但对于那些编写脚本的人来说:

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

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

This is not an answer to the question, but for those who does scripting:

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

it handles / .. ./ etc correctly. I also seems to work on OSX

旧话新听 2024-10-04 06:41:54

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

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

我不确定为什么,但是,在 OS X 上,当脚本“$PWD”调用时,它会扩展为绝对路径。当在命令行上调用 find 命令时,它不会。但这确实是我想要的……享受吧。

I have placed the following script on my system & I call it as a bash alias for when I want to quickly grab the full path to a file in the current dir:

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

I am not sure why, but, on OS X when called by a script "$PWD" expands to the absolute path. When the find command is called on the command line, it doesn't. But it does what I want... enjoy.

心的憧憬 2024-10-04 06:41:54
#! /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.
#! /bin/bash

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

This makes up for the shortcomings of realpath, store it in a shell script fullpath. You can now call:

$ 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.
音盲 2024-10-04 06:41:54

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

realpath() {ruby -e "require 'Pathname'; put Pathname.new('$1').realpath.to_s";}< /code>

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

An alternative to get the absolute path in Ruby:

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

Works with no arguments (current folder) and relative and absolute file or folder path as agument.

思念满溢 2024-10-04 06:41:54

如果您的脚本可能坚持要求存在 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" && pwd) 替换为 result=$(cd "$dir" && 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 才能保证完美的可移植性。

The answer of Alexander Klimetschek is okay if your script may insist on a bash or bash compatible shell being present. It won't work with a shell that is only POSIX conforming.

Also when the final file is a file in root, the output will be //file, which is not technically incorrect (double / are treated like single ones by the system) but it looks strange.

Here's a version that works with every POSIX conforming shell, all external tools it is using are also required by the POSIX standard, and it explicitly handles the root-file case:

#!/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"

Put that into a file and make it executable and you have a CLI tool to quickly get the absolute path of files and directories. Or just copy the function and use it in your own POSIX conforming scripts. It turns relative paths into absolute ones and returns absolute ones as is.

Interesting modifications:

If you replace the line result=$(cd "$dir" && pwd) with result=$(cd "$dir" && pwd -P), then all symbolic links in the path to the final file are resolved as well.

If you are not interested into the first modification, you can optimize the absolute case by returning early:

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"
}

And since the question will arise: Why printf instead of echo?

echo is intended primary to print messages for the user to stdout. A lot of echo behavior that script writers rely on is in fact unspecified. Not even the famous -n is standardized or the usage of \t for tab. The POSIX standard says:

A string to be written to standard output. If the first operand is -n, or if any of the operands contain a character, the results are implementation-defined.
- https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html

Thus whenever you want to write something to stdout and it's not for the purpose of printing a message to the user, the recommendation is to use printf as the behavior of printf is exactly defined. My function uses stdout to pass out a result, this is not a message for the user and thus only using printf guarantees perfect portability.

软甜啾 2024-10-04 06:41:54

在 bash 中:

ls -d“$(pwd)/文件”

也适用于通配符

ls -d "$(pwd)"/*.ts

in bash this:

ls -d "$(pwd)/the-file"

works also with wild card

ls -d "$(pwd)"/*.ts

尤怨 2024-10-04 06:41:54

我使用单行

(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 中起作用。

I use the single line

(cd ${FILENAME%/*}; pwd)

However, this can only be used when $FILENAME has a leading path of any kind (relative or absolute) that actually exists. If there is no leading path at all, then the answer is simply $PWD. If the leading path does not exist, then the answer may be indeterminate, otherwise and the answer is simply ${FILENAME%/*} if the path is absolute.

Putting this all together I would suggest using the following function

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
}

Note also that this only work in bash and compatible shells. I don't believe the substitutions work in the simple shell sh.

千寻… 2024-10-04 06:41:54

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

Hey guys I know it's an old thread but I am just posting this for reference to anybody else who visited this like me. If i understood the question correctly, I think the locate $filename command. It displays the absolute path of the file supplied, but only if it exists.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文