Как получить абсолютный каталог файла в bash?

Я написал bash script, который принимает входной файл в качестве аргумента и читает его.
Этот файл содержит некоторые пути (относительно его расположения) к дополнительным файлам.

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

Итак, как я могу получить папку (и только папку) из входного файла? (В linux.)

Ответ 1

Чтобы получить полный путь, используйте:

readlink -f relative/path/to/file

Чтобы получить каталог файла:

dirname relative/path/to/file

Вы также можете объединить два:

dirname $(readlink -f relative/path/to/file)

Если readlink -f недоступен в вашей системе, вы можете использовать это *:

function myreadlink() {
  (
  cd "$(dirname $1)"         # or  cd "${1%/*}"
  echo "$PWD/$(basename $1)" # or  echo "$PWD/${1##*/}"
  )
}

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

cd $(dirname relative/path/to/file)

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


* Несмотря на то, что myreadlink выше достаточно хорош в контексте этого вопроса, он имеет некоторые ограничения относительно инструмента readlink, предложенного выше. Например, он не правильно следует по ссылке на файл с другим basename.

Ответ 2

Взгляните на страницу руководства для realpath, я использую это и что-то вроде:

CONTAININGDIR = $(realpath ${FILEPATH%/*})

чтобы сделать то, что звучит так, как вы пытаетесь сделать.

Ответ 3

Это будет работать как для файла, так и для папки:

absPath(){
    if [[ -d "$1" ]]; then
        cd "$1"
        echo "$(pwd -P)"
    else 
        cd "$(dirname "$1")"
        echo "$(pwd -P)/$(basename "$1")"
    fi
}

Ответ 4

$cat abs.sh
#!/bin/bash
echo "$(cd "$(dirname "$1")"; pwd -P)"

Некоторые объяснения:

  • Этот script получает относительный путь как аргумент "$1"
  • Затем мы получаем часть dirname этого пути (вы можете передать либо dir или файл в этот script): dirname "$1"
  • Тогда we cd "$(dirname "$1"); в этот относительный dir
  • pwd -P и получить абсолютный путь. Опция -P позволяет избежать символических ссылок
  • В качестве последнего шага мы echo it

Затем запустите свой script:

abs.sh your_file.txt

Ответ 5

Попробуйте наш новый Bash библиотечный продукт realpath-lib в GitHub, который мы предоставили сообществу бесплатно и без использования. Он чист, прост и хорошо документирован, так что это здорово учиться. Вы можете сделать:

get_realpath <absolute|relative|symlink|local file path>

Эта функция является ядром библиотеки:

if [[ -f "$1" ]]
then
    # file *must* exist
    if cd "$(echo "${1%/*}")" &>/dev/null
    then
        # file *may* not be local
        # exception is ./file.ext
        # try 'cd .; cd -;' *works!*
        local tmppwd="$PWD"
        cd - &>/dev/null
    else
        # file *must* be local
        local tmppwd="$PWD"
    fi
else
    # file *cannot* exist
    return 1 # failure
fi

# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success

}

Он Bash 4+, не требует каких-либо зависимостей, а также предоставляет get_dirname, get_filename, get_stemname и validate_path.

Ответ 6

Проблема с приведенным выше ответом идет с файлами ввода с "./" как "./my-file.txt"

Обходной путь (многих):

    myfile="./somefile.txt"
    FOLDER="$(dirname $(readlink -f "${ARG}"))"
    echo ${FOLDER}

Ответ 7

Я использую readlink -f работает над linux

так

FULL_PATH=$(readlink -f filename)
DIR=$(dirname $FULL_PATH)

PWD=$(pwd)

cd $DIR

#<do more work>

cd $PWD