Есть ли команда для получения абсолютного пути по заданному пути?
Например, я хочу, чтобы $ line содержал абсолютный путь к каждому файлу в директории ./etc/
find ./ -type f | while read line; do
echo $line
done
Есть ли команда для получения абсолютного пути по заданному пути?
Например, я хочу, чтобы $ line содержал абсолютный путь к каждому файлу в директории ./etc/
find ./ -type f | while read line; do
echo $line
done
Ответы:
использовать:
find "$(pwd)"/ -type f
чтобы получить все файлы или
echo "$(pwd)/$line"
отображать полный путь (если относительный путь имеет значение для)
$(pwd)
вместо $PWD
? (да, я знаю pwd
, это встроенный)
Попробуй realpath
.
~ $ sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
Чтобы избежать расширения символических ссылок, используйте realpath -s
.
Ответ приходит от команды bash / fish для вывода абсолютного пути к файлу .
realpath
кажется, не доступно на Mac (OS X 10.11 "El Capitan"). :-(
realpath
Похоже, что он недоступен в CentOS 6
brew install coreutils
принесетrealpath
realpath
уже присутствует. Мне не нужно было устанавливать его отдельно.
realpath
доступен на Git для Windows (для меня, по крайней мере).
Если у вас установлен пакет coreutils, вы можете использовать его readlink -f relative_file_name
для получения абсолютного пакета (со всеми разрешенными символическими ссылками).
brew install coreutils
. Однако к исполняемому файлу добавляется ag:greadlink -f relative_file_name
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
UPD Некоторые объяснения
"$1"
dirname "$1"
cd "$(dirname "$1")
в этот относительный каталог и получаем абсолютный путь к нему, выполнив pwd
команду shell$(basename "$1")
echo
этоrealpath
или readlink -f
делать. Например, он не работает с путями, где последний компонент является символической ссылкой.
-P
опцию pwd
команды:echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
За то, что это стоит, я проголосовал за ответ, который был выбран, но хотел поделиться решением. Недостатком является то, что это только 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
ничего не вернете, и в конечном итоге вы получите двойную косую черту.
dirname
, readlink
и basename
. Это помогло мне получить абсолютный путь символической ссылки, а не ее цель.
/home/GKFX
и touch newfile
печатаю, то перед нажатием клавиши ввода вы можете решить, что я имею в виду «create / home / GKFX / newfile», то есть абсолютный путь к файлу, который еще не существует.
Я думаю, что это самый портативный:
abspath() {
cd "$(dirname "$1")"
printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
cd "$OLDPWD"
}
Это не удастся, если путь не существует, хотя.
dirname
утилита ядра GNU, которая, на мой взгляд, не является общей для всех Unixen.
dirname
- стандартная утилита POSIX, см. здесь: pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html
${1##*/}
в течение дня, и теперь, когда я заменил этот мусор, basename "$1"
он, кажется, наконец-то правильно обрабатывает пути, заканчивающиеся на /.
../..
realpath
наверное лучше
Но ...
Начальный вопрос был очень запутанным, с примера, плохо связанного с вопросом, как указано.
Выбранный ответ на самом деле отвечает приведенному примеру, а не на вопрос в заголовке. Первая команда - это ответ (действительно ли это? Я сомневаюсь), и она может обойтись без '/'. И я не вижу, что делает вторая команда.
Несколько вопросов смешаны:
изменение относительного пути в абсолютное, что бы оно ни обозначало, возможно, ничего. ( Как правило, если вы запускаете команду, такую как touch foo/bar
, имя пути foo/bar
должно существовать для вас и, возможно, использоваться в вычислениях, прежде чем файл будет фактически создан. )
может быть несколько абсолютных путей, обозначающих один и тот же файл (или потенциальный файл), особенно из-за символических ссылок (символических ссылок) на пути, но, возможно, по другим причинам (устройство может быть смонтировано дважды только для чтения). Можно или не может хотеть разрешить эксплицитность таких символических ссылок.
добраться до конца цепочки символических ссылок на несимвольный файл или имя. Это может или не может привести к абсолютному пути, в зависимости от того, как это делается. И кто-то может или не может хотеть разрешить его в абсолютном пути.
Команда readlink foo
без опции дает ответ, только если ее аргумент foo
является символической ссылкой, и этот ответ является значением этой символической ссылки. Никакой другой ссылки не последовало. Ответ может быть относительным путем: каким бы ни было значение аргумента символической ссылки.
Тем readlink
не менее, имеет параметры (-f -e или -m), которые будут работать для всех файлов и давать одно абсолютное имя пути (без символьных ссылок) для файла, фактически обозначенного аргументом.
Это прекрасно работает для всего, что не является символической ссылкой, хотя можно использовать абсолютный путь без разрешения промежуточных символических ссылок в пути. Это делается командойrealpath -s foo
В случае аргумента символической ссылки readlink
его параметры снова разрешат все символические ссылки на абсолютном пути к аргументу, но это также будет включать в себя все символические ссылки, которые могут встретиться после значения аргумента. Возможно, вы не захотите этого, если вам нужен абсолютный путь к самой символической ссылке на аргумент, а не к тому, на что он может ссылаться. Опять же, если foo
это символьная ссылка, realpath -s foo
получит абсолютный путь без разрешения символических ссылок, включая указанную в качестве аргумента.
Без -s
опции realpath
делает то же самое
readlink
, за исключением простого чтения значения ссылки, а также некоторых других вещей. Мне просто не понятно, почему readlink
есть свои варианты, создающие, по-видимому, нежелательную избыточность с помощью
realpath
.
Изучение Интернета не говорит о многом, за исключением того, что могут быть некоторые различия между системами.
Вывод: realpath
это лучшая команда для использования с максимальной гибкостью, по крайней мере, для использования, запрошенного здесь.
Мое любимое решение было один на @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="$1"
if [ "$target" == "." ]; then
echo "$(pwd)"
elif [ "$target" == ".." ]; then
echo "$(dirname "$(pwd)")"
else
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
fi
}
Ответ Евгения не совсем сработал для меня, но это сработало:
absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"
Примечание: ваш текущий рабочий каталог не затронут.
Наилучшим решением, imho, является то, которое размещено здесь: https://stackoverflow.com/a/3373298/9724628 .
Для работы требуется python, но, похоже, он охватывает все или большинство крайних случаев и является очень портативным решением.
python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file
Если вы используете Баш на Mac OS X , который ни один не Realpath существовал ни его readlink может напечатать абсолютный путь, вы можете иметь выбор , кроме кода своей собственной версии , чтобы распечатать его. Вот моя реализация:
(чистый удар)
abspath(){
local thePath
if [[ ! "$1" =~ ^/ ]];then
thePath="$PWD/$1"
else
thePath="$1"
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 "$1" ]];then
echo $1|gawk '{
if(substr($0,1,1) != "/"){
path = ENVIRON["PWD"]"/"$0
} else path = $0
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($0)
}
пример:
$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
Если относительный путь является путем к каталогу, попробуйте мой, должно быть лучше:
absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)
echo $absPath
echo "mydir/doc/ mydir/usoe ./mydir/usm" | awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'
Улучшение довольно приятной версии @ ernest-a:
absolute_path() {
cd "$(dirname "$1")"
case $(basename $1) in
..) echo "$(dirname $(pwd))";;
.) echo "$(pwd)";;
*) echo "$(pwd)/$(basename $1)";;
esac
}
Это правильно относится к случаю, когда последним элементом пути является ..
, и в этом случае "$(pwd)/$(basename "$1")"
ответ in @ ernest-a будет выглядеть как accurate_sub_path/spurious_subdirectory/..
.
Если вы хотите преобразовать переменную, содержащую относительный путь, в абсолютный, это работает:
dir=`cd "$dir"`
«CD» эхом без изменения рабочего каталога, потому что выполняется здесь в под-оболочке.
dir=`cd ".."` && echo $dir
Это связанное решение от всех остальных, например, когда происходит realpath
сбой, либо потому, что оно не установлено, либо потому, что оно завершается с кодом ошибки, затем предпринимается попытка следующего решения, пока он не получит правильный путь.
#!/bin/bash
function getabsolutepath() {
local target;
local changedir;
local basedir;
local firstattempt;
target="${1}";
if [ "$target" == "." ];
then
printf "%s" "$(pwd)";
elif [ "$target" == ".." ];
then
printf "%s" "$(dirname "$(pwd)")";
else
changedir="$(dirname "${target}")" && basedir="$(basename "${target}")" && firstattempt="$(cd "${changedir}" && pwd)" && printf "%s/%s" "${firstattempt}" "${basedir}" && return 0;
firstattempt="$(readlink -f "${target}")" && printf "%s" "${firstattempt}" && return 0;
firstattempt="$(realpath "${target}")" && printf "%s" "${firstattempt}" && return 0;
# If everything fails... TRHOW PYTHON ON IT!!!
local fullpath;
local pythoninterpreter;
local pythonexecutables;
local pythonlocations;
pythoninterpreter="python";
declare -a pythonlocations=("/usr/bin" "/bin");
declare -a pythonexecutables=("python" "python2" "python3");
for path in "${pythonlocations[@]}";
do
for executable in "${pythonexecutables[@]}";
do
fullpath="${path}/${executable}";
if [[ -f "${fullpath}" ]];
then
# printf "Found ${fullpath}\\n";
pythoninterpreter="${fullpath}";
break;
fi;
done;
if [[ "${pythoninterpreter}" != "python" ]];
then
# printf "Breaking... ${pythoninterpreter}\\n"
break;
fi;
done;
firstattempt="$(${pythoninterpreter} -c "import os, sys; print( os.path.abspath( sys.argv[1] ) );" "${target}")" && printf "%s" "${firstattempt}" && return 0;
# printf "Error: Could not determine the absolute path!\\n";
return 1;
fi
}
printf "\\nResults:\\n%s\\nExit: %s\\n" "$(getabsolutepath "./asdfasdf/ asdfasdf")" "${?}"
Вы можете использовать подстановку строки bash для любого относительного пути $ line:
line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line
Основная подстановка перед строкой следует формуле
$ {string / # substring / replace},
которая хорошо обсуждается здесь: https://www.tldp.org/LDP/abs/html/string-manipulation.html.
Символ \
отрицает, /
когда мы хотим, чтобы он был частью строки, которую мы находим / заменяем.
Мне не удалось найти решение, которое было бы легко переносимым между Mac OS Catalina, Ubuntu 16 и Centos 7, поэтому я решил сделать это с помощью встроенного Python, и оно хорошо работало для моих скриптов bash.
to_abs_path() {
python -c "import os; print os.path.abspath('$1')"
}
to_abs_path "/some_path/../secrets"