команда bash / fish для вывода абсолютного пути к файлу

261

Вопрос: существует ли команда 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)
  • 0
    Я бы сказал, что ответ @ DennisWilliamson (с опцией -m) лучше (обычно) быть более переносимым и работать с несуществующими файлами.
  • 0
    Или ответ Флимма; оба являются хорошими решениями. Баннир, однако, лучше всего отвечает на мой первоначальный вопрос.
Показать ещё 1 комментарий
Теги:
path

17 ответов

261
Лучший ответ

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

~ $ realpath .bashrc
/home/username/.bashrc
  • 106
    +1, очень хорошая программа. Но обратите внимание, что это внешняя команда (а не встроенная оболочка), которая может отсутствовать в каждой системе по умолчанию, т.е. вам может потребоваться ее установка. В Debian он находится в отдельном пакете с тем же именем.
  • 0
    Именно то, что я искал, спасибо! Вопрос только в том, почему я не смог найти это сам ...
Показать ещё 16 комментариев
264

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

readlink -e /foo/bar/baz
  • 46
    Я бы предпочел использовать '-f' вместо '-e', чтобы мы могли видеть абсолютный путь к несуществующему файлу.
  • 5
    Это выглядит как самый простой для меня, но при этом быть портативным. readlink - это порт ядра gnu coreutils, поэтому он будет установлен практически на любой дистрибутив Linux, кроме некоторых встроенных.
Показать ещё 7 комментариев
160
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
  • 7
    Не забудьте процитировать все вещи. Если вы не понимаете, почему, попробуйте свою программу на файл ab (два пробела между a и b, SO ест один из них).
  • 1
    также попробуйте это на "/" это превращается в "///"
Показать ещё 9 комментариев
62
$ readlink -m FILE
/path/to/FILE

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

  • 11
    ссылка для чтения не найдена на OSX
  • 0
    Ницца. Это также работает с файлами / каталогами, которые существуют, но не являются символическими ссылками.
Показать ещё 4 комментария
56

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

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

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

вы можете использовать его следующим образом:

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

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

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

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

Он переносимый и не требует ни 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/..

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

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
}
  • 0
    Хорошая функция, но, видимо, вы не поняли вопрос. Я хотел что-то для интерактивного использования, а не сценарии.
  • 0
    @dhardy. Не уверен, что понимаю ваш комментарий. Что в предложенном здесь решении исключает использование из интерактивной среды? ... кстати, как и все другие альтернативные ответы, представленные на этой странице.
Показать ещё 11 комментариев
47

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

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

код:

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, но исправляет случай файла.

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

  • 0
    Благодарю. Это то, что я иду на OSX
  • 0
    Это не работает для каталогов с пробелами, например: $ abspath 'ab c/file.txt' Это потому, что аргумент cd не заключен в кавычки. Чтобы преодолеть это, вместо цитирования всего аргумента в echo (есть ли причина для этих кавычек?), Приводите только аргументы пути. Т.е. заменить echo "$(cd ${1%/*}; pwd)/${1##*/}" на echo $(cd "${1%/*}"; pwd)/${1##*/}
Показать ещё 8 комментариев
23

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

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

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

find $PWD

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

  • 1
    я не впился этим комментарием при первом прочтении; Ключевым моментом здесь является то, что если вы дадите абсолютный путь к команде поиска, то она выдаст результаты в абсолютном пути. таким образом, использование $ PWD - это абсолютный путь, по которому вы находитесь, поэтому вы получите вывод как абсолютный.
  • 3
    Если вы полагаетесь на PWD , вы можете просто использовать $PWD/$filename .
Показать ещё 5 комментариев
13

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

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

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

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

  • 1
    Выглядит портативно для меня. С другой стороны, сломается, например, на имя файла, содержащее перевод строки.
  • 0
    Да, вы правы. Я удалил grep полностью.
Показать ещё 4 комментария
7

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

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

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

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

Это вызывает несколько замечаний:

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

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

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

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

  • 0
    Я не против того, чтобы меня понизили, но мне нравится понимать, почему я могу чему-то научиться, как техническому, так и относительно того, что считается правильной практикой на сайте. Ну ... по крайней мере это побудило меня зарегистрироваться в Meta Stack Overflow, чтобы лучше понять местную социологию. Я рекомендую это. - Тем не менее, если у кого-то есть мнение о неуместности моего ответа, мне это интересно.
  • 1
    (а) на вопрос есть правильный ответ от 2 + 1/2 года назад, (б) существует (один) абсолютный путь, соответствующий относительному пути (что я и хотел), хотя, возможно, не к файлу, как вы указал. Кстати, любые комментарии о realpath против readlink или даже о символических ссылках realpath к тому, что я спросил.
Показать ещё 13 комментариев
7

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

realpath() { for f in "$@"; do echo ${f}(:A); done }
  • 0
    Это замечательно :)
  • 0
    Вау, это элегантное решение !!
2

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

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

Я не уверен, почему, но в OS X при вызове script "$ PWD" расширяется до абсолютного пути. Когда команда find вызывается в командной строке, это не так. Но он делает то, что я хочу... наслаждаюсь.

  • 0
    $PWD всегда имеет абсолютный путь к рабочему каталогу. Кроме того, find не потерпит косых черт, поэтому вы не отвечаете на вопрос в том виде, в котором он был задан. Более быстрый способ сделать то, что вы хотите сделать, это просто echo "$PWD/$1"
1

Для каталогов dirname происходит сбой для ../ и возвращает ./.

функция nolan6000 может быть изменена, чтобы исправить это:

get_abs_filename() {
  # $1 : relative filename
  if [ -d "${1%/*}" ]; then
    echo "$(cd ${1%/*}; pwd)/${1##*/}"
  fi
}
  • 1
    Добро пожаловать на ТАК! Для небольших изменений и замечаний добавление комментария к существующему ответу может быть более подходящим, чем добавление ответа, особенно если в этом скопированном ответе отсутствует много другой информации исходного ответа. Как только вы набрали чуть больше репутации, вы можете добавлять комментарии к ответам других людей. А пока попробуйте собрать репутацию, задавая уникальные, ценные вопросы или предоставляя хорошие ответы.
  • 1
    Поскольку вы имеете в виду ответ nolan6000, обратите внимание, что автор dhardy уже прокомментировал, что он не примет ответ nolan6000, потому что он не ищет сценарий. Так что, строго говоря, ваш ответ не отвечает на вопрос.
Показать ещё 2 комментария
0

Ответ dogbane с описанием того, что происходит:

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

Пояснение:

  • Этот script получает относительный путь как аргумент "$1"
  • Затем мы получаем часть dirname этого пути (вы можете передать либо dir или файл в этот script): dirname "$1"
  • Затем мы cd "$(dirname "$1") в этот относительный dir и получаем для него абсолютный путь, запустив pwd команду оболочки
  • После этого мы добавляем базовое имя к абсолютному пути: $(basename "$1")
  • В качестве последнего шага мы echo it
0

Альтернатива для получения абсолютного пути в Ruby:

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

Работает без аргументов (текущая папка) и относительного и абсолютного пути к файлам или папкам в качестве агимента.

0

Это не ответ на вопрос, но для тех, кто выполняет скриптинг:

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

он правильно обрабатывает/.../и т.д. Я также работаю над OSX

0
#! /bin/bash

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

Это компенсирует недостатки realpath, сохраните его в оболочке script 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.
  • 0
    Что это решает? realpath "foo bar" -> /home/myname/foo bar . Если вы не можете взять в кавычки аргументы командной строки, это не realpath .
  • 0
    Согласитесь, это скорее удобная обертка.
-2

Эй, ребята, я знаю, что это старая нить, но я просто размещаю это для ссылки на кого-нибудь другого, кто посетил это, как я. Если я правильно понял вопрос, я думаю, что команда locate $filename. Он отображает абсолютный путь к предоставленному файлу, но только если он существует.

  • 4
    locate - это утилита для поиска файлов / путей по имени. Он может выполнять эту работу, но также может находить другие совпадения и может не находить существующий файл, если сначала не updatedb как root.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню