Как получить абсолютный путь к файлу через Shell (BASH/ZSH/SH)?
Вопрос: Существует ли простая команда 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 ответ(ов)
Попробуйте использовать команду readlink
, которая позволяет разрешать символические ссылки:
readlink -e /foo/bar/baz
Этот скрипт на 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
.
Вот перевод на русский в стиле ответа на вопрос на 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
}
Надеюсь, это поможет вам в работе!
Команда readlink -m FILE
возвращает абсолютный путь к файлу, указанному в FILE
, преобразуя любые символические ссылки и очищая все лишние компоненты пути. Важное преимущество этой команды заключается в том, что она работает даже в случае, если файл не существует. Это делает её более удобной по сравнению с командами readlink -e FILE
или realpath
, которые требуют существования файла для корректной работы.
Команда find
может оказаться полезной:
find $PWD -name ex*
find $PWD -name example.log
Эти команды перечисляют все файлы в текущем каталоге и подкаталогах, имена которых соответствуют указанному шаблону. Если вы ожидаете получить лишь несколько результатов (например, если это каталог, находящийся внизу дерева с небольшим количеством файлов), вы можете упростить команду до:
find $PWD
Я использую это на Solaris 10, где отсутствуют другие упомянутые утилиты.
Как выводить команды оболочки по мере их выполнения
Как указать приватный SSH-ключ для выполнения команды shell в Git?
Как сделать паузу в shell-скрипте на одну секунду перед продолжением?
Как получить пароль из оболочки без вывода в терминал?
Проверьте, нужно ли выполнять pull в Git