Bash: получить абсолютный путь заданный относительный
есть ли команда для получения абсолютного пути с учетом относительного пути?
например, я хочу, чтобы $line содержал абсолютный путь каждого файла в dir ./etc/
find ./ -type f | while read line; do
echo $line
done
16 ответов:
использование:
find $(pwd)/ -type fчтобы получить все файлы или
echo $(pwd)/$lineдля отображения полного пути (если относительный путь имеет значение)
попробовать
realpath.~ $ sudo apt-get install realpath ~ $ realpath .bashrc /home/username/.bashrcответ приходит от "команда bash/fish для печати абсолютного пути к файлу".
Если у вас установлен пакет coreutils, вы обычно можете использовать
readlink -f relative_file_nameчтобы получить абсолютный (со всеми разрешенными символическими ссылками)
#! /bin/sh echo "$(cd "$(dirname "")"; pwd)/$(basename "")"UPD объяснения
- этот скрипт получает относительный путь в качестве аргумента
""- тогда мы получим dirname часть этого пути (вы можете передать либо dir, либо файл в этот скрипт):
dirname ""- затем мы
cd "$(dirname "")в этот относительный dir и получить абсолютный путь для него, запустивpwdкомандная оболочка- после этого мы добавляем basename к абсолютному пути:
$(basename "")- как заключительный шаг мы
echoэто
для чего это стоит, я голосовал за ответ, который был выбран, но хотели бы поделиться решением. Недостатком является то, что это только Linux - я потратил около 5 минут, пытаясь найти эквивалент OSX, прежде чем перейти к переполнению стека. Я уверен, что это там, хотя.
в Linux вы можете использовать
readlink -eвместе сdirname.$(dirname $(readlink -e ../../../../etc/passwd))доходность
/etc/и
dirnameС сестройbasenameпросто этот имя файла$(basename ../../../../../passwd)доходность
passwdсложите все вместе..
F=../../../../../etc/passwd echo "$(dirname $(readlink -e $F))/$(basename $F)"доходность
/etc/passwdвы в безопасности, если вы нацелены на каталог,
basenameничего не вернуть и вы просто получите двойные косые черты в конечном итоге.
Я думаю, что это самый портативный:
abspath() { cd "$(dirname "")" printf "%s/%s\n" "$(pwd)" "$(basename "")" cd "$OLDPWD" }это не удастся, если путь не существует, хотя.
realpathлучшено ...
первоначальный вопрос был очень запутан для начала, с примером плохо связано с вопросом, как указано.
выбранный ответ фактически отвечает приведенному примеру, а не вообще вопрос в названии. Первая команда это ответ (это правда ? Я сомневаюсь), и мог бы обойтись и без '/'. И я не вижу что делает вторая команда.
несколько вопросов смешанный :
изменение относительного пути в абсолютный, что бы это ни было обозначает, возможно, ничего. (как правило, если вы выполняете такую команду, как
touch foo/bar, в путьfoo/barдолжен существовать для вас, и, возможно, будут использоваться в вычисление, прежде чем файл будет фактически создан.)может быть несколько абсолютных путей, которые обозначают один и тот же файл (или потенциальный файл), особенно из-за символических ссылок (symlinks) На путь, но, возможно, по другим причинам (устройство может быть монтируется дважды как только для чтения). Можно или не нужно решать эксплицитность таких символических ссылок.
добраться до конца цепочки символических ссылок не симлинк файл или имя. Это может или не может дать абсолютное имя пути, в зависимости от того, как это делается. И можно, а можно и не хотеть разрешите его в абсолютное имя пути.
команда
readlink fooбез опции дает ответ только если его аргументfooявляется символической ссылкой, и этот ответ является значением этого символьная ссылка. Никакой другой ссылки не следует. Ответ может быть относительным путем: каково бы ни было значение аргумента symlink.однако,
readlinkимеет опции (-f-e или-m), которые будут работать для всех файлы, и дать один абсолютный путь (тот, который без символических ссылок) файл фактически обозначается аргументом.это прекрасно работает для всего, что не является символической ссылкой, если можно жаждать использование абсолютного пути без разрешения промежуточного символические ссылки на пути. Это делается командой
realpath -s fooв случае, если аргумент ссылки
readlinkсо своими опциями будет снова разрешите все символические ссылки на абсолютном пути к аргументу, но это также будет включать все символические ссылки, которые могут встретиться после значения аргумента. Вы можете не хотеть этого, если вы хотите абсолютный путь к самой символической ссылке аргумента, а не к чему-либо он может ссылаться на. Опять же, еслиfoo- символическая ссылка,realpath -s fooбудет получить абсолютный путь без разрешения символьных ссылок, включая одну приведено в качестве аргумента.без ,
realpathделает почти то же самое, что иreadlink, за исключением простого чтения значения ссылки, а также нескольких прочие вещи. Мне просто непонятно почемуreadlinkимеет варианты, создающие, по-видимому, нежелательную избыточность с помощьюrealpath.изучение интернета не говорит намного больше, за исключением что там может быть некоторые вариации в разных системах.
вывод :
realpathЭто лучшая команда для использования, с наиболее гибкость, по крайней мере для использования здесь.
ответ Евгения не совсем сработал для меня, но это сделало:
absolute="$(cd $(dirname $file); pwd)/$(basename $file)"Примечание, ваш текущий рабочий каталог не затронут.
в случае
find, вероятно, проще всего просто дать абсолютный путь для его поиска, например:find /etc find `pwd`/subdir_of_current_dir/ -type f
если вы используете bash на Mac OS X, который ни имеет realpath не существовало ни ее более ранних версий может напечатать абсолютный путь, вы можете иметь выбор, но закодировать свою собственную версию, чтобы распечатать его. Вот моя реализация:
(чисто Баш)
abspath(){ local thePath if [[ ! "" =~ ^/ ]];then thePath="$PWD/" else thePath="" fi echo "$thePath"|( IFS=/ read -a parr declare -a outp for i in "${parr[@]}";do case "$i" in ''|.) continue ;; ..) len=${#outp[@]} if ((len==0));then continue else unset outp[$((len-1))] fi ;; *) len=${#outp[@]} outp[$len]="$i" ;; esac done echo /"${outp[*]}" ) }(используйте gawk)
abspath_gawk() { if [[ -n "" ]];then echo |gawk '{ if(substr(,1,1) != "/"){ path = ENVIRON["PWD"]"/" } else path = split(path, a, "/") n = asorti(a, b,"@ind_num_asc") for(i in a){ if(a[i]=="" || a[i]=="."){ delete a[i] } } n = asorti(a, b, "@ind_num_asc") m = 0 while(m!=n){ m = n for(i=1;i<=n;i++){ if(a[b[i]]==".."){ if(b[i-1] in a){ delete a[b[i-1]] delete a[b[i]] n = asorti(a, b, "@ind_num_asc") break } else exit 1 } } } n = asorti(a, b, "@ind_num_asc") if(n==0){ printf "/" } else { for(i=1;i<=n;i++){ printf "/"a[b[i]] } } }' fi }(чистый BSD awk)
#!/usr/bin/env awk -f function abspath(path, i,j,n,a,b,back,out){ if(substr(path,1,1) != "/"){ path = ENVIRON["PWD"]"/"path } split(path, a, "/") n = length(a) for(i=1;i<=n;i++){ if(a[i]==""||a[i]=="."){ continue } a[++j]=a[i] } for(i=j+1;i<=n;i++){ delete a[i] } j=0 for(i=length(a);i>=1;i--){ if(back==0){ if(a[i]==".."){ back++ continue } else { b[++j]=a[i] } } else { if(a[i]==".."){ back++ continue } else { back-- continue } } } if(length(b)==0){ return "/" } else { for(i=length(b);i>=1;i--){ out=out"/"b[i] } return out } } BEGIN{ if(ARGC>1){ for(k=1;k<ARGC;k++){ print abspath(ARGV[k]) } exit } } { print abspath() }пример:
$ abspath I/am/.//..//the/./god/../of///.././war /Users/leon/I/the/war
мое любимое решение один по @EugenKonkov, потому что это не подразумевало наличие других утилит (пакет coreutils).
но это не для относительных путей "." и." ."так вот немного улучшенная версия обработки этих особых случаях.
он по-прежнему не работает, если у пользователя нет разрешения на
cdв родительский каталог относительного пути, однако.#! /bin/sh # Takes a path argument and returns it as an absolute path. # No-op if the path is already absolute. function to-abs-path { local target="" if [ "$target" == "." ]; then echo "$(pwd)" elif [ "$target" == ".." ]; then echo "$(dirname "$(pwd)")" else echo "$(cd "$(dirname "")"; pwd)/$(basename "")" fi }
похоже на ответ @ernest-a, но без влияния
$OLDPWDили определить новую функцию, которую вы могли бы запустить подрешетку(cd <path>; pwd)$ pwd /etc/apache2 $ cd ../cups $ cd - /etc/apache2 $ (cd ~/..; pwd) /Users $ cd - /etc/cups
если относительный путь-это путь к каталогу, то попробуйте мой, должен быть лучшим:
absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null) echo $absPath