команда bash / fish для вывода абсолютного пути к файлу - PullRequest
373 голосов
/ 12 октября 2010

Вопрос: существует ли простая команда 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)

Ответы [ 17 ]

445 голосов
/ 12 октября 2010

Попробуйте realpath.

$ realpath example.txt
/home/username/example.txt
295 голосов
/ 12 октября 2010

Попробуйте readlink, который разрешит символические ссылки:

readlink -e /foo/bar/baz
228 голосов
/ 12 октября 2010
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
75 голосов
/ 17 января 2014

Забудьте о readlink и realpath, которые могут или не могут быть установлены в вашей системе.

Расширение на ответ собачьей страхи выше здесь это выражается как функция:

#!/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 выводит абсолютный путь к текущему каталогу при вызове без аргументов.

Почему мне нравится это решение?

Он переносим и не требует ни readlink, ни realpath, чего часто не существует при установке по умолчанию данного дистрибутива 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
}
74 голосов
/ 27 февраля 2013
$ readlink -m FILE
/path/to/FILE

Это лучше, чем readlink -e FILE или realpath, поскольку оно работает, даже если файл не существует.

59 голосов
/ 11 апреля 2014

Этот относительный путь к преобразователю абсолютного пути функция оболочки

  • не требует никаких утилит (только cd и pwd)
  • работает для каталогов и файлов
  • ручки .. и .
  • обрабатывает пробелы в 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

Примечание. Это основано на ответах от nolan6000 и bsingh , но исправляет регистр файлов.

Я также понимаю, что первоначальный вопрос был о существующей утилите командной строки. Но так как этот вопрос, похоже, является вопросом стекового потока для этого, включая сценарии оболочки, которые хотят иметь минимальные зависимости, я поместил это решение сценария здесь, чтобы найти его позже:)

23 голосов
/ 12 октября 2011

Команда find может помочь

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

Перечисляет все файлы в или ниже текущего каталога с именами, соответствующими шаблону. Вы можете упростить его, если получите только несколько результатов (например, каталог в нижней части дерева, содержащий несколько файлов), просто

find $PWD

Я использую это в Solaris 10, в котором нет других упомянутых утилит.

15 голосов
/ 12 октября 2010

Если у вас нет утилит readlink или realpath, вы можете использовать следующую функцию, которая работает в bash и zsh (не уверен насчет остальных).

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

Это также работает для несуществующих файлов (какработает ли python os.path.abspath).

К сожалению abspath ./../somefile не избавляется от точек.

9 голосов
/ 24 сентября 2012

Вот функция zsh-only, которая мне нравится за ее компактность.Он использует модификатор расширения 'A' - см. Zshexpn (1).

realpath() { for f in "$@"; do echo ${f}(:A); done }
7 голосов
/ 19 мая 2013

Как правило, в файле не существует такой вещи, как the absolute path (это утверждение означает, что в общем случае их может быть несколько), следовательно, использование определенной статьи the не подходит)absolute path - это любой путь, начинающийся с корня "/" и обозначающий файл без неоднозначности независимо от рабочего каталога (см., Например, wikipedia ).

A relative pathпуть, который нужно интерпретировать, начиная с другого каталога.Это может быть рабочий каталог, если это relative path, которым манипулирует приложение (хотя и не обязательно).Когда он находится в символьной ссылке в каталоге, он, как правило, должен относиться к этому каталогу (хотя пользователь может иметь в виду иное использование).

Следовательно, абсолютный путь - это просто путь относительнокорневой каталог.

Путь (абсолютный или относительный) может содержать или не содержать символические ссылки.Если это не так, это также несколько непроницаемо для изменений в структуре связи, но это не обязательно требуется или даже желательно.Некоторые люди называют canonical path (или canonical file name или resolved path) absolute path, в котором все символические ссылки были разрешены, т. Е. Заменены путем на путь, куда они ссылаются.Команды realpath и readlink обе ищут канонический путь, но только у realpath есть возможность получить абсолютный путь, не удосуживаясь разрешить символические ссылки (наряду с несколькими другими опциями, чтобы получить различные виды путей, абсолютные илиотносительно некоторого каталога).

Это требует нескольких замечаний:

  1. символические ссылки могут быть разрешены, только если все, на что они должны ссылаться, уже создано, что, очевидно, не всегдадело.Команды realpath и readlink имеют опции для учета этого.
  2. каталог на пути может впоследствии стать символической ссылкой, что означает, что путь больше не является canonical.Следовательно, эта концепция зависит от времени (или среды).
  3. даже в идеальном случае, когда все символические ссылки могут быть разрешены, в файле может быть еще более одного canonical path по двум причинам:
    • раздел, содержащий файл, возможно, был смонтирован одновременно (ro) в нескольких точках монтирования.
    • могут быть жесткие ссылки на файл, то есть, по сути, файл существует в нескольких разных каталогах.

Следовательно, даже при гораздо более ограничительном определении canonical path может быть несколько канонических путей к файлу.Это также означает, что квалификатор canonical несколько неадекватен, поскольку обычно подразумевает понятие уникальности.

Это расширяет краткое обсуждение темы в ответе на другой похожий вопрос на Bash: получить абсолютныйотносительный путь

Мой вывод таков, что realpath лучше спроектирован и гораздо более гибок, чем readlink.Единственное использование readlink, которое не охватывается realpath, - это вызов без опции, возвращающий значение символической ссылки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...