7

Как получить абсолютный путь к файлу через Shell (BASH/ZSH/SH)?

5

Вопрос: Существует ли простая команда sh/bash/zsh/fish/... для вывода абсолютного пути к файлу, который я укажу?

Описание проблемы: Я нахожусь в директории /a/b и хотел бы вывести полный путь к файлу c в командной строке, чтобы я мог легко вставить его в другую программу: /a/b/c. Это просто, но небольшая программа, которая выполняет эту задачу, могла бы сэкономить мне несколько секунд при обработке длинных путей, что в итоге накапливается. Поэтому меня удивляет, что я не могу найти стандартную утилиту для этой задачи — разве её действительно нет?

Вот пример реализации, abspath.py:

#!/usr/bin/python
# Автор: Diggory Hardy <[email protected]>
# Лицензия: общественное достояние
# Цель: вывести абсолютный путь всех входящих путей

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, "Использование: ", sys.argv[0], " ПУТЬ."
    sys.exit(1)

5 ответ(ов)

3

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

readlink -e /foo/bar/baz
3

Этот скрипт на bash выполняет несколько операций для преобразования пути к файлу, переданному в качестве аргумента. Давайте разберем его по частям:

#! /bin/sh

Эта строка указывает операционной системе, что необходимо использовать sh для выполнения скрипта.

echo "$(...)

echo используется для вывода строки, а содержимое $() - это команда, которая будет выполнена.

cd "$(dirname -- "$1")" >/dev/null;

Сначала с помощью dirname извлекается путь к каталогу (директория) из полного пути, переданного в качестве аргумента $1. Затем происходит переход в этот каталог (cd). >/dev/null используется для подавления вывода команды, чтобы он не отображался на экране.

pwd -P

Команда pwd -P выводит полный путь к текущему рабочему каталогу после выполнения команды cd, разрешая любые символические ссылки.

/$(basename -- "$1")

Здесь basename получает имя файла из полного пути, переданного в $1, а затем добавляет этот файл к полученному пути.

Таким образом, весь скрипт возвращает абсолютный путь к файлу, переданному в качестве аргумента $1, разрешая при этом возможные символические ссылки в директориях. Это может быть полезно, если вы хотите получить "реальный" путь к файлу.

Если, например, вы хотите использовать этот скрипт, вызовите его с полным путем к файлу в качестве аргумента:

./your_script.sh /path/to/your/file.txt

Он вернет абсолютный путь к file.txt.

1

Вот перевод на русский в стиле ответа на вопрос на StackOverflow:


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

Расширяя ответ dogbane, вот как это можно выразить в виде функции:

#!/bin/bash
get_abs_filename() {
  # $1 : относительное имя файла
  echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
}

Теперь вы можете использовать эту функцию следующим образом:

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

Как это работает и почему?

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

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

Оно портативно и не требует наличие readlink или realpath, которые часто отсутствуют в стандартной установке дистрибутивов Linux/Unix.

Что если директория не существует?

Как указано выше, функция выдаст ошибку и выведет сообщение на stderr, если указанный путь к директории не существует. Это может быть не тем, что вы хотите. Вы можете расширить функцию, чтобы обрабатывать эту ситуацию:

#!/bin/bash
get_abs_filename() {
  # $1 : относительное имя файла
  if [ -d "$(dirname "$1")" ]; then
    echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
  fi
}

Теперь она вернет пустую строку, если одна из родительских директорий не существует.

Как вы обрабатываете завершающие '..' или '.' в вводе?

На самом деле, это дает абсолютный путь в таком случае, но не минимальный. Например, он будет выглядеть так:

/Users/bob/Documents/..

Если вы хотите разрешить '..', вам нужно изменить скрипт следующим образом:

get_abs_filename() {
  # $1 : относительное имя файла
  filename=$1
  parentdir=$(dirname "${filename}")

  if [ -d "${filename}" ]; then
      echo "$(cd "${filename}" && pwd)"
  elif [ -d "${parentdir}" ]; then
    echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")"
  fi
}

Надеюсь, это поможет вам в работе!

0

Команда readlink -m FILE возвращает абсолютный путь к файлу, указанному в FILE, преобразуя любые символические ссылки и очищая все лишние компоненты пути. Важное преимущество этой команды заключается в том, что она работает даже в случае, если файл не существует. Это делает её более удобной по сравнению с командами readlink -e FILE или realpath, которые требуют существования файла для корректной работы.

0

Команда find может оказаться полезной:

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

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

find $PWD

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь