Я ищу простую команду, которую можно использовать в Bash для поиска абсолютного и канонизированного пути к файлу в OS X (аналогично ``readlink -f'' в Linux).
Следующий пример сеанса bash описывает [вымышленную] утилиту под названием ``abspath'', которая демонстрирует желаемое поведение:
$ pwd
/Users/guyfleegman
$ ls -lR
drwxr-xr-x 4 guyfleegman crew 136 Oct 30 02:09 foo
./foo:
-rw-r--r-- 1 guyfleegman crew 0 Oct 30 02:07 bar.txt
lrwxr-xr-x 1 guyfleegman crew 7 Oct 30 02:09 baz.txt -> bar.txt
$ abspath .
/Users/guyfleegman
$ abspath foo
/Users/guyfleegman/foo
$ abspath ./foo/bar.txt
/Users/guyfleegman/foo/bar.txt
$ abspath foo/baz.txt
/Users/guyfleegman/foo/baz.txt
Как и в случае с последним вызовом ``abspath'' в приведенном выше примере, я бы предпочел, чтобы он не разрешал символические ссылки автоматически, но я не собираюсь быть здесь слишком придирчивым.
решение1
function abspath() { pushd . > /dev/null; if [ -d "$1" ]; then cd "$1"; dirs -l +0; else cd "`dirname \"$1\"`"; cur_dir=`dirs -l +0`; if [ "$cur_dir" == "/" ]; then echo "$cur_dir`basename \"$1\"`"; else echo "$cur_dir/`basename \"$1\"`"; fi; fi; popd > /dev/null; }
Примеры:
abspath / => /
abspath /.DS_Store => /.DS_Store
abspath ~ => /Users/mschrag
cd /tmp; abspath . => /tmp
cd /; abspath .DS_Store => /.DS_Store
решение2
Я не думаю, что есть встроенная команда, которая это делает.Джесси Уилсоннаписал bash-скрипт для этого:
#!/bin/bash
cd -P -- "$(dirname -- "$1")" &&
printf '%s\n' "$(pwd -P)/$(basename -- "$1")"
Однако это не работает хорошо для путей, расположенных непосредственно под /
, таких как /etc
(печать //etc
), а также .
и ..
(печать /cwd/.
в обоих случаях). Я пытался изменить его, но мой недостаточный bash-fu подвел меня.
Вот мое предложение:
#!/usr/bin/env python
import os.path
import sys
for arg in sys.argv[1:]:
print os.path.abspath(arg)
Сохранить как /usr/bin/abspath
или что-то вроде этого и сделать его исполняемым. Пример вывода:
Servus08:~ danielbeck$ abspath .
/Users/danielbeck
Servus08:~ danielbeck$ abspath /tmp
/tmp
Servus08:~ danielbeck$ abspath Documents
/Users/danielbeck/Documents
Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/tmp
/Users/danielbeck/Documents
Если выделатьЕсли вы хотите разрешить символическую ссылку, измените print
строку следующим образом:
print os.path.realpath(os.path.abspath(arg))
чтобы получить это:
Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/private/tmp
/Users/danielbeck/Documents
решение3
Одним из вариантов было бы просто установить coreutils и использовать greadlink -f
. Он разрешает символические ссылки и работает с /Foo/
или ~/foo.txt
, если они не существуют, но не с /Foo/foo.txt
, если /Foo/
не существует.
$ brew install coreutils
$ greadlink -f /etc
/private/etc
$ greadlink -f ~/Documents/
/Users/lauri/Documents
$ greadlink -f ..
/Users
$ greadlink -f //etc/..////
/private
$ greadlink -f /Foo
/Foo
$ greadlink -f /Foo/foo.txt
$
Это не разрешает символические ссылки и не работает ни с тем, ни с /Foo/foo.txt
другим.
abspath() {
if [ -d "$1" ]; then
( cd "$1"; dirs -l +0 )
else
( cd "$(dirname "$1")"; d=$(dirs -l +0); echo "${d%/}/${1##*/}" )
fi
}
abspath /etc # /etc
abspath ~/Foo/foo.txt # doesn't work
abspath ~/Foo # works
abspath .
abspath ./
abspath ../
abspath ..
abspath /
abspath ~
abspath ~/
abspath ~/Documents
abspath /\"\ \'
abspath /etc/../etc/
abspath /private//etc/
abspath /private//
abspath //private # //private
abspath ./aa.txt
abspath aa.tar.gz
abspath .aa.txt
abspath /.DS_Store
abspath ~/Documents/Books/
dirs -l
выполняет расширение тильды. dirs +0
печатает только самый верхний каталог, если в стеке есть другие каталоги.
решение4
Если у вас установлен модуль File::Spec для Perl, вы можете просто сделать это:
perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "\n"'