zaLinux.ru

Как в Bash узнать абсолютный путь до файла


Что такое абсолютный и относительный пути

Абсолютный путь содержит полный перечень папок, в которых находится файл, начиная от корня файловой системы.

Пример абсолютного пути: /home/mial/bin/myfile.txt

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

Относительный путь указывает на расположение файла относительно текущей папки. Примеры относительных путей:

  • myfile.txt
  • ./myfile.txt
  • bin/myfile.txt
  • ../../bin/myfile.txt

Преимущество относительного пути в том, что обычно он обозначается более короткой записью как например myfile.txt — означает одноимённый файл в текущей папке. Очевидно, что при смене рабочей директории относительный путь до файла станет другим.

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

realpath

Первый вариант — использовать команду realpath:

realpath timeout

Привет вывода абсолютного пути:

/home/mial/bin/timeout

Эта программа является частью coreutils.

По умолчанию эта программа преобразует символические ссылки (опция -P) и показывает расположение файла даже если он не существует (опция -m) — то есть эти опции указывать необязательно.

Фактически, по умолчанию работа программы сводится к тому, что к указанному аргументу она добавляет текущую рабочую папку, то есть можно узнать абсолютный путь даже до файла, который не существует:

realpath not_exist
/home/mial/bin/not_exist

Если вас это не устраивает, то используйте опцию -e — тогда если указанный файл не существует, то вместо вывода абсолютного пути будет показано сообщение об ошибке.

readlink

Аналогичную функцию выполняет и команда readlink.

Если вы хотите показать абсолютный путь только для существующих файлов, то используйте опцию -e:


readlink -e timeout
/home/mial/bin/timeout

Если вас не волнует, существует ли файл, то используйте опцию -f (не требует существование последнего компонента) или опцию -m (не требует существование какого-либо компонента пути):

readlink -f not_exist
/home/mial/bin/not_exist

realpath и readlink не найдены

UNIX системы — это не только многочисленные дистрибутивы Linux. В некоторых из них команды realpath и readlink могут отсутствовать. Если они отсутствуют и вы не хотите или не можете устанавливать дополнительные бинарные файлы, то выход всё равно есть.

Создайте файл, например, realpath.sh и скопируйте в него:

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

Запускать так:


bash realpath.sh ФАЙЛ

Этот же вариант в виде функции:

function realpath { echo $(cd $(dirname $1); pwd)/$(basename $1); }

Вот эта же функция в продвинутом варианте — дополнительно обрабатывает ситуацию, когда директория не существует, а также если во вводе присутствуют '..' или '.'

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
}

Ещё один вариант в виде функции оболочки, который:

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

Код:

function abspath() {
    # генерирует абсолютный путь из относительного
    # $1     : относительное имя файла
    # возвращает : абсолютный путь
    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
}

И ещё одна функция, записанная в одну строку и работающая в bash и zsh (другие не проверялись):

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

Может работать с несуществующими файлами.


Рекомендуемые статьи:

2 Комментарии

  1. basarga

    Зачем использовать какие-то скрипты с pwd, readlink или realpath для ТЕКУЩЕЙ директории, если можно просто использовать pwd?!!

    pwd

    /home/bestoloch

    Или просто прочитай глобальную переменную $PWD:

    echo $PWD

    /home/bestoloch

    Вдумайся, что такое ТЕКУЩАЯ директория! Это просто значение в переменной $PWD! "cd /home" и PWD='/home' это ОДНО И ТОЖЕ! Просто абстракция, благодаря которой ты думаешь, что "переходишь" из директории в директорию. А теперь включи мозг, и сообрази, как узнать путь к запускаемому скрипту, если запускаешь его не из ТЕКУЩЕЙ директории, а из, примеру, соседней?

    1. Alexey (Автор записи)

      Во-первых, вам надо что-то делать со своей манерой общения: даже если вы считаете себя самым умным и считаете что много знаете, разговаривать в таком тоне с вами никто не обязан.

      А вы далеко не самый умный — показанные способы подходят на все случаи жизни, в том числе, когда получаем путь для файла, который является ссылкой. С помощью pwd или переменной это не сработает.

      И самое главное, pwd не поможет, если нужно получить абсолютный путь не просто для файла в текущей папке, а для относительного пути (например, ../../bin/myfile.txt), а методы в статье предназначены именно для таких ситуаций, чтобы любые относительные пути преобразовывать в абсолютные.

      Следующее отличие — если мы просто будем добавлять к имени файла вывод команды pwd, то мы никогда не узнаем, существует ли этот файл на самом деле или нет. В статье рассмотрены оба варианта: когда в случае отсутствия файла будет или не будет возвращена ошибка.

      Ну и так далее. Ваш комментарий нелеп. Видимо, вы даже не понимаете, о чём говорится в статье.

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *