Имеет ли значение, существует ли он вообще /foo/barили /fooвообще существует, или вас интересует только аспект манипуляции со строками в соответствии с правилами имен путей?
Чен Леви
5
@ twalberg ... это как-то придумано ...
Камило Мартин
2
@CamiloMartin не надуманный вообще - это именно то , что задает вопрос - прообразы /foo/bar/..к /foo, и используя bashкоманду. Если есть другие требования, которые не заявлены, то, возможно, они должны быть ...
Twalberg
14
@twalberg Ты слишком много делаешь TDD -_- '
Камило Мартин
Ответы:
194
если вы хотите скомпоновать часть имени файла из пути, «dirname» и «basename» - ваши друзья, и «realpath» также удобен.
dirname /foo/bar/baz
# /foo/bar
basename /foo/bar/baz
# baz
dirname $( dirname /foo/bar/baz )# /foo
realpath ../foo
# ../foo: No such file or directory
realpath /tmp/../tmp/../tmp
# /tmp
realpath альтернативы
Если realpathваша оболочка не поддерживается, вы можете попробовать
readlink -f /path/here/..
Также
readlink -m /path/there/../../
Работает так же, как
realpath -s /path/here/../../
в том, что путь не должен существовать, чтобы быть нормализованным.
И то, realpathи другое readlinkпроисходит от основных утилит GNU, так что, скорее всего, вы получите либо оба, либо ни одного. Если я правильно помню, версия readlink на Mac немного отличается от версии GNU: - \
Antoine 'hashar' Musso
101
Я не знаю, есть ли прямая команда bash, чтобы сделать это, но я обычно делаю
Это нормализует, но не разрешает мягкие ссылки. Это может быть ошибка или особенность. :-)
Адам Лисс
4
Это также имеет проблему, если определен $ CDPATH; потому что «cd foo» переключится на любой каталог «foo», который является подкаталогом $ CDPATH, а не просто «foo», который находится в текущем каталоге. Я думаю, что вам нужно сделать что-то вроде: CDPATH = "" cd "$ {dirToNormalize}" && pwd -P.
MJS
7
Ответ Тима определенно самый простой и самый портативный. С CDPATH легко работать: dir = "$ (unset CDPATH && cd" $ dir "&& pwd)"
Дэвид Блевинс,
2
Это может быть очень опасно ( rm -rf $normalDir), если dirToNormalize не существует!
Фрэнк Мейленаар
4
Да, вероятно, лучше всего использовать &&комментарий @ DavidBlevins.
Элиас Дорнелес
54
Попробуй realpath. Ниже приведен источник в полном объеме, настоящим пожертвовано в общественное достояние.
// realpath.c: display the absolute path to a file or directory.// Adam Liss, August, 2007// This program is provided "as-is" to the public domain, without express or// implied warranty, for any non-profit use, provided this notice is maintained.#include<stdio.h>#include<stdlib.h>#include<string.h>#include<libgen.h>#include<limits.h>staticchar*s_pMyName;void usage(void);int main(int argc,char*argv[]){char
sPath[PATH_MAX];
s_pMyName = strdup(basename(argv[0]));if(argc <2)
usage();
printf("%s\n", realpath(argv[1], sPath));return0;}void usage(void){
fprintf(stderr,"usage: %s PATH\n", s_pMyName);
exit(1);}
Это стандартно для Ubuntu / BSD, а не Centos / OSX
Эрик Аронести
4
Вы должны по-настоящему ударить по части с помощью «Бонуса: это команда bash, доступная везде!» часть о realpath. Это также, случается, мой любимый, но вместо того, чтобы собрать ваш инструмент из источника. Это все в супертяжелом весе, и большую часть времени вы просто хотите readlink -f... Кстати, readlinkэто тоже НЕ встроенная bash, а часть coreutilsUbuntu.
Томаш Гандор
4
Вы сказали, что жертвуете это на всеобщее достояние, но в заголовке также написано «для любого некоммерческого использования» - вы действительно хотите пожертвовать это на всеобщее достояние? Это означало бы, что его можно использовать в коммерческих некоммерческих целях, а также в коммерческих целях ...
me_and
36
Портативное и надежное решение - использовать python, который установлен практически везде (включая Darwin). У вас есть два варианта:
abspath возвращает абсолютный путь, но не разрешает символические ссылки:
У BSD нет флага -f, что означает, что это не удастся даже на последней MacOS Mojave и многих других системах. Забудьте об использовании -f, если вам нужна переносимость, это влияет на множество ОС.
Сорин
1
@sorin. Вопрос не в Mac, а в Linux.
mattalxndr
14
readlinkстандарт bash для получения абсолютного пути Он также имеет преимущество, заключающееся в возврате пустых строк, если пути или пути не существует (учитывая флаги для этого).
Чтобы получить абсолютный путь к каталогу, который может существовать или не существовать, но чьи родители существуют, используйте:
abspath=$(readlink -f $path)
Чтобы получить абсолютный путь к каталогу, который должен существовать вместе со всеми родителями:
abspath=$(readlink -e $path)
Чтобы канонизировать данный путь и следовать символическим ссылкам, если они существуют, но в противном случае игнорировать отсутствующие каталоги и просто возвращать путь в любом случае, это:
abspath=$(readlink -m $path)
Единственным недостатком является то, что readlink будет следовать ссылкам. Если вы не хотите переходить по ссылкам, вы можете использовать это альтернативное соглашение:
abspath=$(cd ${path%/*}&& echo $PWD/${path##*/})
Это приведет к переходу в директорию $ path и распечатает текущий каталог вместе с файловой частью $ path. Если это не удалось chdir, вы получите пустую строку и ошибку на stderr.
readlinkхороший вариант, если он доступен. Версия OS X не поддерживает опции -eили -f. В первых трех примерах вы должны иметь двойные кавычки $pathдля обработки пробелов или подстановочных знаков в имени файла. +1 для расширения параметра, но это имеет уязвимость безопасности. Если pathпусто, это будет cdв вашем домашнем каталоге. Вам нужны двойные кавычки. abspath=$(cd "${path%/*}" && echo "$PWD/${path##*/}")
toxalot
Это был просто пример. Если вы одержимы безопасностью, то вам вообще не следует использовать bash или любой другой вариант оболочки. Кроме того, у bash есть свои проблемы, когда речь идет о кроссплатформенной совместимости, а также проблемы с изменением функциональности между основными версиями. OSX - это всего лишь одна из многих платформ с проблемами, относящимися к сценариям оболочки, не говоря уже о том, что она основана на BSD. Когда вам нужно быть действительно мультиплатформенным, вы должны быть POSIX-совместимым, поэтому расширение параметров действительно выходит за рамки. Посмотрите на Solaris или HP-UX некоторое время.
Крейг
6
Здесь нет никакого смысла в оскорблении, но важно указать на такие неясные вопросы, как это. Я просто хотел бы получить быстрый ответ на эту тривиальную проблему, и я бы доверял этому коду любой / все ввод, если бы не комментарий выше. Также важно поддерживать OS-X в этих обсуждениях bash. Есть много команд, которые, к сожалению, не поддерживаются в OS-X, и многие форумы принимают это как должное при обсуждении Bash, что означает, что мы будем продолжать сталкиваться с множеством кросс-платформенных проблем, если только они не будут решены раньше, чем позже.
Ребс
13
Старый вопрос, но есть гораздо более простой способ, если вы имеете дело с полными путями на уровне оболочки:
abspath = "$ (cd" $ path "&& pwd)"
Поскольку cd происходит в подоболочке, он не влияет на основной скрипт.
Два варианта, предполагающие, что встроенные команды вашей оболочки принимают -L и -P:
Использование компакт-диска гарантирует, что у вас всегда есть абсолютный каталог, даже если скрипт запускается такими командами, как ./script.sh, который, без cd / pwd, часто дает просто ... Бесполезно, если сценарий делает CD позже.
Как отметил Адам Лисс, realpathон не входит в комплект поставки. Который является позором, потому что это лучшее решение. Предоставленный исходный код великолепен, и я, вероятно, начну использовать его сейчас. Вот то, что я использовал до сих пор, и я делюсь здесь только для полноты:
get_abs_path(){local PARENT_DIR=$(dirname "$1")
cd "$PARENT_DIR"local ABS_PATH="$(pwd)"/"$(basename "$1")"
cd ->/dev/null
echo "$ABS_PATH"}
Если вы хотите разрешить символические ссылки, просто замените pwdна pwd -P.
Один вопрос с pwd -Pопцией для этого случая ... Подумайте, что произойдет, если бы $(basename "$1")была символическая ссылка на файл в другом каталоге. pwd -PТолько разрешает символические ссылки в части каталога пути, но не часть BASENAME.
Я подозреваю, что это не удастся, если аргумент не является каталогом. Предположим, я хочу знать, куда ведет / usr / bin / java?
Эдвард Фальк
1
Если вы знаете, что это файл, вы можете pushd $(dirname /usr/bin/java)попробовать.
schmunk
5
Не совсем ответ, но, возможно, дополнительный вопрос (первоначальный вопрос не был явным):
readlinkхорошо, если вы действительно хотите следовать символическим ссылкам. Но есть также вариант использования для простой нормализации ./и ../и //последовательности, которые могут быть сделаны чисто синтаксически, без канонизации символических ссылок. readlinkне хорошо для этого, и ни один realpath.
for f in $paths;do(cd $f; pwd);done
работает для существующих путей, но ломается для других.
sedСценарий , казалось бы хорошим выбором, за исключением того, что вы не можете итеративно заменить последовательности ( /foo/bar/baz/../..-> /foo/bar/..-> /foo) , не используя что - то вроде Perl, который не является безопасным предположить на всех системах, или с помощью какой - то уродливый цикл , чтобы сравнить выход sedк его вклад.
FWIW, однострочник с использованием Java (JDK 6+):
jrunscript -e 'for (var i = 0; i < arguments.length; i++) {println(new java.io.File(new java.io.File(arguments[i]).toURI().normalize()))}' $paths
realpathимеет -sвозможность не разрешить символические ссылки и только разрешать ссылки /./, /../и удалить лишние /символы. В сочетании с этой -mопцией realpathработает только с именем файла и не касается какого-либо фактического файла. Это звучит как идеальное решение. Но, увы, realpathдо сих пор отсутствует во многих системах.
toxalot
Удаление ..компонентов не может быть сделано синтаксически, когда задействованы символические ссылки. /one/two/../threeэто не то же самое , как /one/threeесли бы twoэто символическая ссылка на /foo/bar.
jrw32982 поддерживает Монику
@ jrw32982 да, как я уже сказал в своем ответе, это для случая использования, когда канонизация символической ссылки не нужна или не нужна.
Джесси Глик
@JesseGlick это не просто вопрос, хотите ли вы канонизировать символические ссылки. Ваш алгоритм на самом деле дает неправильный ответ. Чтобы ваш ответ был правильным, вы должны были бы априори знать, что не было никаких символических ссылок (или что они были только определенной формы). Ваш ответ говорит о том, что вы не хотите их канонизировать, а не о том, что на пути нет символических ссылок.
jrw32982 поддерживает Монику
В некоторых случаях нормализация должна выполняться без использования какой-либо фиксированной существующей структуры каталогов. Нормализация URI аналогична. В этих случаях присуще ограничение, заключающееся в том, что результат, как правило, будет неправильным, если рядом с каталогом, к которому применяется результат, окажутся символические ссылки.
Джесси Глик
5
Я опаздываю на вечеринку, но это решение, которое я разработал после прочтения нескольких тем вроде этого:
resolve_dir(){(builtin cd `dirname "${1/#~/$HOME}"`'/'`basename "${1/#~/$HOME}"`2>/dev/null;if[ $?-eq 0];then pwd;fi)}
Это разрешит абсолютный путь в $ 1, будет хорошо играть с ~, сохранит символические ссылки там, где они есть, и это не помешает вашему стеку каталогов. Возвращает полный путь или ничего, если он не существует. Он ожидает, что $ 1 будет каталогом и, возможно, потерпит неудачу, если это не так, но это легко проверить самостоятельно.
Разговорчивый и немного поздний ответ. Мне нужно написать один, так как я застрял на старшей RHEL4 / 5. Я обрабатываю абсолютные и относительные ссылки и упрощаю записи //, /./ и somedir /../.
Попробуйте наш новый продукт библиотеки Bash realpath-lib, который мы поместили на GitHub, для бесплатного и свободного использования. Он тщательно документирован и является отличным инструментом обучения.
Он разрешает локальные, относительные и абсолютные пути и не имеет никаких зависимостей, кроме Bash 4+; так что должно работать где угодно. Это бесплатно, чисто, просто и поучительно.
Однако это не разрешает символические ссылки. Realpath обрабатывает пути, начинающиеся с корня, и по ходу идет по символическим ссылкам. Все это делает, свернуть родительские ссылки.
Мартин Питерс
2
Основываясь на ответе @ Andre, у меня могла бы быть немного лучшая версия, если кто-то ищет решение без петель, полностью основанное на обработке строк. Это также полезно для тех, кто не хочет разыменовывать любые символические ссылки, что является недостатком использования realpathили readlink -f.
Работает на bash версий 3.2.25 и выше.
shopt -s extglob
normalise_path(){local path="$1"# get rid of /../ example: /one/../two to /two
path="${path//\/*([!\/])\/\.\./}"# get rid of /./ and //* example: /one/.///two to /one/two
path="${path//@(\/\.\/|\/+(\/))//}"# remove the last '/.'
echo "${path%%/.}"}
$ normalise_path /home/codemedic/../codemedic////.config
/home/codemedic/.config
Это хорошая идея, но я потратил 20 минут, пытаясь заставить это работать на разных версиях bash. Оказывается, чтобы это работало, нужно включить параметр оболочки extglob, а по умолчанию это не так. Когда речь заходит о функциональности bash, важно указать как необходимую версию, так и параметры, отличные от заданных по умолчанию, поскольку эти данные могут различаться в разных ОС. Например, последняя версия Mac OSX (Yosemite) поставляется только с устаревшей версией bash (3.2).
drwatsoncode
Извините @ricovox; Я сейчас обновил их. Мне не терпится узнать точную версию Bash, которая у вас есть. Вышеприведенная формула (обновленная) работает на CentOS 5.8, которая поставляется с bash 3.2.25
ϲοδεMεδιϲ
Извините за путаницу. Этот код работал на моей версии Mac OSX bash (3.2.57), как только я включил extglob. Моя заметка о версиях bash была более общей (на самом деле это относится и к другому ответу, касающемуся регулярных выражений в bash).
drwatsoncode 13.10.15
2
Я ценю ваш ответ, хотя. Я использовал его в качестве основы для себя. Между прочим, я заметил несколько случаев, когда ваш сбой: (1) Относительные пути hello/../world(2) Точки в имени файла /hello/..world(3) Точки после двойной косой черты /hello//../world(4) Точка до или после двойной косой черты /hello//./worldили /hello/.//world (5) Родитель после текущей: /hello/./../world/ (6) Родитель after Parent: /hello/../../worldи т. д. - некоторые из них можно исправить, используя цикл для исправления, пока путь не перестанет меняться. (Также удалите dir/../, /dir/..но не удалите dir/..с конца.)
drwatsoncode
0
Основываясь на превосходном фрагменте Python от Loveborg, я написал это:
#!/bin/sh# Version of readlink that follows links to the end; good for Mac OS Xfor file in"$@";dowhile[-h "$file"];do
l=`readlink $file`case"$l"in/*) file="$l";;*) file=`dirname "$file"`/"$l"esacdone#echo $file
python -c "import os,sys; print os.path.abspath(sys.argv[1])""$file"done
Вот короткий тестовый пример с некоторыми искривленными пробелами в путях, чтобы полностью использовать цитату
mkdir -p "/tmp/test/ first path "
mkdir -p "/tmp/test/ second path "
echo "hello">"/tmp/test/ first path / red .txt "
ln -s "/tmp/test/ first path / red .txt ""/tmp/test/ second path / green .txt "
cd "/tmp/test/ second path "
fullpath " green .txt "
cat " green .txt "
Я знаю, что это древний вопрос. Я все еще предлагаю альтернативу. Недавно я столкнулся с той же проблемой и не нашел ни одной существующей и переносимой команды для этого. Поэтому я написал следующий сценарий оболочки, который включает в себя функцию, которая может сделать свое дело.
#! /bin/sh function normalize {local rc=0local ret
if[ $# -gt 0 ] ; then# invalidif["x`echo $1 | grep -E '^/\.\.'`"!="x"];then
echo $1
return-1fi# convert to absolute pathif["x`echo $1 | grep -E '^\/'`"=="x"];then
normalize "`pwd`/$1"return $?fi
ret=`echo $1 | sed 's;/\.\($\|/\);/;g' | sed 's;/[^/]*[^/.]\+[^/]*/\.\.\($\|/\);/;g'`else
read line
normalize "$line"return $?fiif["x`echo $ret | grep -E '/\.\.?(/|$)'`"!="x"];then
ret=`normalize "$ret"`
rc=$?fi
echo "$ret"return $rc
}
Я сделал встроенную функцию только для обработки этого с акцентом на максимально возможную производительность (для удовольствия). Он не разрешает символические ссылки, поэтому он в основном такой же, как realpath -sm.
## A bash-only mimic of `realpath -sm`. ## Give it path[s] as argument[s] and it will convert them to clean absolute paths
abspath (){
${*+false}&&{>&2 echo $FUNCNAME: missing operand;return1;};local c s p IFS='/';## path chunk, absolute path, input path, IFS for splitting paths into chunkslocal-i r=0;## return valuefor p in"$@";docase"$p"in## Check for leading backslashes, identify relative/absolute path'')((r|=1));continue;;//[!/]*)>&2 echo "paths =~ ^//[^/]* are impl-defined; not my problem";((r|=2));continue;;/*);;*) p="$PWD/$p";;## Prepend the current directory to form an absolute pathesac
s='';for c in $p;do## Let IFS split the path at '/'scase $c in### NOTE: IFS is '/'; so no quotes needed here''|.);;## Skip duplicate '/'s and '/./'s..) s="${s%/*}";;## Trim the previous addition to the absolute path string*) s+=/$c;;### NOTE: No quotes here intentionally. They make no difference, it seemsesac;done;
echo "${s:-/}";## If xpg_echo is set, use `echo -E` or `printf $'%s\n'` insteaddonereturn $r;}
Примечание. Эта функция не обрабатывает пути, начинающиеся с //, поскольку ровно две двойные косые черты в начале пути являются поведением, определяемым реализацией. Тем не менее, он справляется /, ///и так далее, просто отлично.
Эта функция, кажется, правильно обрабатывает все крайние случаи, но могут быть некоторые из них, с которыми я не имел дело.
Замечание по производительности: при вызове с тысячами аргументов abspathработает примерно в 10 раз медленнее, чем realpath -sm; при вызове с одним аргументом abspathработает> в 110 раз быстрее, чем realpath -smна моей машине, в основном из-за того, что нет необходимости каждый раз выполнять новую программу.
/foo/bar
или/foo
вообще существует, или вас интересует только аспект манипуляции со строками в соответствии с правилами имен путей?/foo/bar/..
к/foo
, и используяbash
команду. Если есть другие требования, которые не заявлены, то, возможно, они должны быть ...Ответы:
если вы хотите скомпоновать часть имени файла из пути, «dirname» и «basename» - ваши друзья, и «realpath» также удобен.
realpath
альтернативыЕсли
realpath
ваша оболочка не поддерживается, вы можете попробоватьТакже
Работает так же, как
в том, что путь не должен существовать, чтобы быть нормализованным.
источник
realpath
и другоеreadlink
происходит от основных утилит GNU, так что, скорее всего, вы получите либо оба, либо ни одного. Если я правильно помню, версия readlink на Mac немного отличается от версии GNU: - \Я не знаю, есть ли прямая команда bash, чтобы сделать это, но я обычно делаю
и это работает хорошо.
источник
rm -rf $normalDir
), если dirToNormalize не существует!&&
комментарий @ DavidBlevins.Попробуй
realpath
. Ниже приведен источник в полном объеме, настоящим пожертвовано в общественное достояние.источник
realpath
. Это также, случается, мой любимый, но вместо того, чтобы собрать ваш инструмент из источника. Это все в супертяжелом весе, и большую часть времени вы просто хотитеreadlink -f
... Кстати,readlink
это тоже НЕ встроенная bash, а частьcoreutils
Ubuntu.Портативное и надежное решение - использовать python, который установлен практически везде (включая Darwin). У вас есть два варианта:
abspath
возвращает абсолютный путь, но не разрешает символические ссылки:python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file
realpath
возвращает абсолютный путь и при этом разрешает символические ссылки, генерируя канонический путь:python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
В каждом случае
path/to/file
может быть как относительный, так и абсолютный путь.источник
readlink
доступно на OS X, только не с-f
опцией. Портативные обходные пути обсуждаются здесь .Используйте утилиту readlink из пакета coreutils.
источник
readlink
стандарт bash для получения абсолютного пути Он также имеет преимущество, заключающееся в возврате пустых строк, если пути или пути не существует (учитывая флаги для этого).Чтобы получить абсолютный путь к каталогу, который может существовать или не существовать, но чьи родители существуют, используйте:
Чтобы получить абсолютный путь к каталогу, который должен существовать вместе со всеми родителями:
Чтобы канонизировать данный путь и следовать символическим ссылкам, если они существуют, но в противном случае игнорировать отсутствующие каталоги и просто возвращать путь в любом случае, это:
Единственным недостатком является то, что readlink будет следовать ссылкам. Если вы не хотите переходить по ссылкам, вы можете использовать это альтернативное соглашение:
Это приведет к переходу в директорию $ path и распечатает текущий каталог вместе с файловой частью $ path. Если это не удалось chdir, вы получите пустую строку и ошибку на stderr.
источник
readlink
хороший вариант, если он доступен. Версия OS X не поддерживает опции-e
или-f
. В первых трех примерах вы должны иметь двойные кавычки$path
для обработки пробелов или подстановочных знаков в имени файла. +1 для расширения параметра, но это имеет уязвимость безопасности. Еслиpath
пусто, это будетcd
в вашем домашнем каталоге. Вам нужны двойные кавычки.abspath=$(cd "${path%/*}" && echo "$PWD/${path##*/}")
Старый вопрос, но есть гораздо более простой способ, если вы имеете дело с полными путями на уровне оболочки:
Поскольку cd происходит в подоболочке, он не влияет на основной скрипт.
Два варианта, предполагающие, что встроенные команды вашей оболочки принимают -L и -P:
Лично мне этот поздний подход редко нужен, если я по какой-то причине не увлечен символическими ссылками.
К вашему сведению: вариант получения начальной директории скрипта, который работает, даже если скрипт позже меняет свою текущую директорию.
Использование компакт-диска гарантирует, что у вас всегда есть абсолютный каталог, даже если скрипт запускается такими командами, как ./script.sh, который, без cd / pwd, часто дает просто ... Бесполезно, если сценарий делает CD позже.
источник
Как отметил Адам Лисс,
realpath
он не входит в комплект поставки. Который является позором, потому что это лучшее решение. Предоставленный исходный код великолепен, и я, вероятно, начну использовать его сейчас. Вот то, что я использовал до сих пор, и я делюсь здесь только для полноты:Если вы хотите разрешить символические ссылки, просто замените
pwd
наpwd -P
.источник
pwd -P
опцией для этого случая ... Подумайте, что произойдет, если бы$(basename "$1")
была символическая ссылка на файл в другом каталоге.pwd -P
Только разрешает символические ссылки в части каталога пути, но не часть BASENAME.Мое недавнее решение было:
На основании ответа Тима Уиткомба.
источник
pushd $(dirname /usr/bin/java)
попробовать.Не совсем ответ, но, возможно, дополнительный вопрос (первоначальный вопрос не был явным):
readlink
хорошо, если вы действительно хотите следовать символическим ссылкам. Но есть также вариант использования для простой нормализации./
и../
и//
последовательности, которые могут быть сделаны чисто синтаксически, без канонизации символических ссылок.readlink
не хорошо для этого, и ни одинrealpath
.работает для существующих путей, но ломается для других.
sed
Сценарий , казалось бы хорошим выбором, за исключением того, что вы не можете итеративно заменить последовательности (/foo/bar/baz/../..
->/foo/bar/..
->/foo
) , не используя что - то вроде Perl, который не является безопасным предположить на всех системах, или с помощью какой - то уродливый цикл , чтобы сравнить выходsed
к его вклад.FWIW, однострочник с использованием Java (JDK 6+):
источник
realpath
имеет-s
возможность не разрешить символические ссылки и только разрешать ссылки/./
,/../
и удалить лишние/
символы. В сочетании с этой-m
опциейrealpath
работает только с именем файла и не касается какого-либо фактического файла. Это звучит как идеальное решение. Но, увы,realpath
до сих пор отсутствует во многих системах...
компонентов не может быть сделано синтаксически, когда задействованы символические ссылки./one/two/../three
это не то же самое , как/one/three
если быtwo
это символическая ссылка на/foo/bar
.Я опаздываю на вечеринку, но это решение, которое я разработал после прочтения нескольких тем вроде этого:
Это разрешит абсолютный путь в $ 1, будет хорошо играть с ~, сохранит символические ссылки там, где они есть, и это не помешает вашему стеку каталогов. Возвращает полный путь или ничего, если он не существует. Он ожидает, что $ 1 будет каталогом и, возможно, потерпит неудачу, если это не так, но это легко проверить самостоятельно.
источник
Разговорчивый и немного поздний ответ. Мне нужно написать один, так как я застрял на старшей RHEL4 / 5. Я обрабатываю абсолютные и относительные ссылки и упрощаю записи //, /./ и somedir /../.
источник
Попробуйте наш новый продукт библиотеки Bash realpath-lib, который мы поместили на GitHub, для бесплатного и свободного использования. Он тщательно документирован и является отличным инструментом обучения.
Он разрешает локальные, относительные и абсолютные пути и не имеет никаких зависимостей, кроме Bash 4+; так что должно работать где угодно. Это бесплатно, чисто, просто и поучительно.
Ты можешь сделать:
Эта функция является ядром библиотеки:
Он также содержит функции для get_dirname, get_filename, get_ stemname и validate_path. Попробуйте это на разных платформах и помогите улучшить его.
источник
Проблема в
realpath
том, что он недоступен в BSD (или OSX в этом отношении). Вот простой рецепт, извлеченный из довольно старой (2009 г.) статьи из Linux Journal , которая довольно переносима:Обратите внимание, что этот вариант также не требует пути для существования.
источник
Основываясь на ответе @ Andre, у меня могла бы быть немного лучшая версия, если кто-то ищет решение без петель, полностью основанное на обработке строк. Это также полезно для тех, кто не хочет разыменовывать любые символические ссылки, что является недостатком использования
realpath
илиreadlink -f
.Работает на bash версий 3.2.25 и выше.
источник
hello/../world
(2) Точки в имени файла/hello/..world
(3) Точки после двойной косой черты/hello//../world
(4) Точка до или после двойной косой черты/hello//./world
или/hello/.//world
(5) Родитель после текущей:/hello/./../world/
(6) Родитель after Parent:/hello/../../world
и т. д. - некоторые из них можно исправить, используя цикл для исправления, пока путь не перестанет меняться. (Также удалитеdir/../
,/dir/..
но не удалитеdir/..
с конца.)Основываясь на превосходном фрагменте Python от Loveborg, я написал это:
источник
Это работает, даже если файл не существует. Для этого требуется каталог, содержащий файл.
источник
realpath -e
Мне нужно решение, которое сделало бы все три:
realpath
иreadlink -f
аддоныНи в одном из ответов не было ни № 1, ни № 2. Я добавил # 3, чтобы спасти других от дальнейшего бритья.
Вот короткий тестовый пример с некоторыми искривленными пробелами в путях, чтобы полностью использовать цитату
источник
Я знаю, что это древний вопрос. Я все еще предлагаю альтернативу. Недавно я столкнулся с той же проблемой и не нашел ни одной существующей и переносимой команды для этого. Поэтому я написал следующий сценарий оболочки, который включает в себя функцию, которая может сделать свое дело.
https://gist.github.com/bestofsong/8830bdf3e5eb9461d27313c3c282868c
источник
Я сделал встроенную функцию только для обработки этого с акцентом на максимально возможную производительность (для удовольствия). Он не разрешает символические ссылки, поэтому он в основном такой же, как
realpath -sm
.Примечание. Эта функция не обрабатывает пути, начинающиеся с
//
, поскольку ровно две двойные косые черты в начале пути являются поведением, определяемым реализацией. Тем не менее, он справляется/
,///
и так далее, просто отлично.Эта функция, кажется, правильно обрабатывает все крайние случаи, но могут быть некоторые из них, с которыми я не имел дело.
Замечание по производительности: при вызове с тысячами аргументов
abspath
работает примерно в 10 раз медленнее, чемrealpath -sm
; при вызове с одним аргументомabspath
работает> в 110 раз быстрее, чемrealpath -sm
на моей машине, в основном из-за того, что нет необходимости каждый раз выполнять новую программу.источник
Сегодня я обнаружил, что вы можете использовать
stat
команду для определения путей.Так что для директории типа "~ / Documents":
Вы можете запустить это:
stat -f %N ~/Documents
Чтобы получить полный путь:
/Users/me/Documents
Для символических ссылок вы можете использовать формат% Y:
stat -f %Y example_symlink
Который может вернуть результат как:
/usr/local/sbin/example_symlink
Параметры форматирования могут отличаться в других версиях * NIX, но они работают для меня в OSX.
источник
stat -f %N ~/Documents
линия красная селедка ... ваша оболочка меняет~/Documents
с/Users/me/Documents
, аstat
просто печатать его аргумент дословно.Простое решение с использованием
node.js
:источник