Як аргументи мого сценарію є кілька шляхів до файлів. Звичайно, вони можуть бути відносними (або містити ~). Але для написаних мною функцій потрібні абсолютні шляхи, але не вирішені символічні посилання.
Чи є якась функція для цього?
Як аргументи мого сценарію є кілька шляхів до файлів. Звичайно, вони можуть бути відносними (або містити ~). Але для написаних мною функцій потрібні абсолютні шляхи, але не вирішені символічні посилання.
Чи є якась функція для цього?
readlink
вирішує символічні посилання; ОП цього не хоче.
echo $(cd some_directory && pwd)
, не вирішує символічне посилання, не вдається, якщо якийсь_каталог не існує. робочий каталог не впливає. або призначити змінній MY_PATH=$(cd some_directory && pwd)
.
Відповіді:
MY_PATH=$(readlink -f $YOUR_ARG)
вирішить відносні шляхи, такі як "./"
і"../"
Подумайте і про це ( джерело ):
#!/bin/bash
dir_resolve()
{
cd "$1" 2>/dev/null || return $? # cd to desired directory; if fail, quell any error messages but return exit status
echo "`pwd -P`" # output full, link-resolved path
}
# sample usage
if abs_path="`dir_resolve \"$1\"`"
then
echo "$1 resolves to $abs_path"
echo pwd: `pwd` # function forks subshell, so working directory outside function is not affected
else
echo "Could not reach $1"
fi
man pwd
: "-P Відобразити поточний фізичний робочий каталог (усі символічні посилання вирішено)", просто видаліть-P
readlink -f
функціональність на OS X, ви можете використовувати Homebrew, а потім запустити: $ brew install coreutils
Потім ви можете використовувати greadlink -f
.
function abspath {
if [[ -d "$1" ]]
then
pushd "$1" >/dev/null
pwd
popd >/dev/null
elif [[ -e "$1" ]]
then
pushd "$(dirname "$1")" >/dev/null
echo "$(pwd)/$(basename "$1")"
popd >/dev/null
else
echo "$1" does not exist! >&2
return 127
fi
}
який використовує pushd
/, popd
щоб потрапити в стан, де pwd
це корисно.
DIRSTACK
і нічого іншого. Приємне рішення!
sh
сумісності, pushd; cd <dir>; <cmd>; popd
його можна замінити на (cd <dir>; <cmd>)
.
Простий однокласний:
function abs_path {
(cd "$(dirname '$1')" &>/dev/null && printf "%s/%s" "$PWD" "${1##*/}")
}
Використання:
function do_something {
local file=$(abs_path $1)
printf "Absolute path to %s: %s\n" "$1" "$file"
}
do_something $HOME/path/to/some\ where
Я все ще намагаюся зрозуміти, як я можу змусити його не звертати уваги на те, чи існує шлях чи ні (тому його можна використовувати також при створенні файлів).
cd -
після цього скидати його?
${1##*/}
на, basename
хоча, не поміщаючи його в окрему змінну, шляхи з пробілами не працюють належним чином.
на OS X, який ви можете використовувати
stat -f "%N" YOUR_PATH
у Linux у вас може бути realpath
виконуваний файл. якщо ні, то може працювати наступне (не лише для посилань):
readlink -c YOUR_PATH
stat -f "%N" PATH
дає мені точно такий самий шлях, яким я його пройшов.
Можливо, це є більш читабельним і не використовує під оболонку і не змінює поточний каталог:
dir_resolve() {
local dir=`dirname "$1"`
local file=`basename "$1"`
pushd "$dir" &>/dev/null || return $? # On error, return error code
echo "`pwd -P`/$file" # output full, link-resolved path with filename
popd &> /dev/null
}
самостійно редагувати, я щойно помітив, що OP сказав, що він не шукає вирішених символьних посилань:
"Але для написаних мною функцій потрібні абсолютні шляхи, але не вирішені символічні посилання."
Тож здогадайтесь, це зрештою не так відповідає його питанню. :)
Оскільки за ці роки я з цим стикався багато разів, і цього разу мені знадобилася портативна версія pure bash, яку я міг би використовувати на OSX та Linux, я продовжив і написав одну:
Тут живе жива версія:
https://github.com/keen99/shell-functions/tree/master/resolve_path
але задля SO, ось поточна версія (я відчуваю, що вона добре перевірена .. але я відкрита для відгуків!)
Можливо, не складно змусити це працювати для звичайної оболонки Борна (sh), але я не намагався ... Мені занадто подобається $ FUNCNAME. :)
#!/bin/bash
resolve_path() {
#I'm bash only, please!
# usage: resolve_path <a file or directory>
# follows symlinks and relative paths, returns a full real path
#
local owd="$PWD"
#echo "$FUNCNAME for $1" >&2
local opath="$1"
local npath=""
local obase=$(basename "$opath")
local odir=$(dirname "$opath")
if [[ -L "$opath" ]]
then
#it's a link.
#file or directory, we want to cd into it's dir
cd $odir
#then extract where the link points.
npath=$(readlink "$obase")
#have to -L BEFORE we -f, because -f includes -L :(
if [[ -L $npath ]]
then
#the link points to another symlink, so go follow that.
resolve_path "$npath"
#and finish out early, we're done.
return $?
#done
elif [[ -f $npath ]]
#the link points to a file.
then
#get the dir for the new file
nbase=$(basename $npath)
npath=$(dirname $npath)
cd "$npath"
ndir=$(pwd -P)
retval=0
#done
elif [[ -d $npath ]]
then
#the link points to a directory.
cd "$npath"
ndir=$(pwd -P)
retval=0
#done
else
echo "$FUNCNAME: ERROR: unknown condition inside link!!" >&2
echo "opath [[ $opath ]]" >&2
echo "npath [[ $npath ]]" >&2
return 1
fi
else
if ! [[ -e "$opath" ]]
then
echo "$FUNCNAME: $opath: No such file or directory" >&2
return 1
#and break early
elif [[ -d "$opath" ]]
then
cd "$opath"
ndir=$(pwd -P)
retval=0
#done
elif [[ -f "$opath" ]]
then
cd $odir
ndir=$(pwd -P)
nbase=$(basename "$opath")
retval=0
#done
else
echo "$FUNCNAME: ERROR: unknown condition outside link!!" >&2
echo "opath [[ $opath ]]" >&2
return 1
fi
fi
#now assemble our output
echo -n "$ndir"
if [[ "x${nbase:=}" != "x" ]]
then
echo "/$nbase"
else
echo
fi
#now return to where we were
cd "$owd"
return $retval
}
ось класичний приклад, завдяки brew:
%% ls -l `which mvn`
lrwxr-xr-x 1 draistrick 502 29 Dec 17 10:50 /usr/local/bin/mvn@ -> ../Cellar/maven/3.2.3/bin/mvn
використовуйте цю функцію, і вона поверне шлях -real-:
%% cat test.sh
#!/bin/bash
. resolve_path.inc
echo
echo "relative symlinked path:"
which mvn
echo
echo "and the real path:"
resolve_path `which mvn`
%% test.sh
relative symlinked path:
/usr/local/bin/mvn
and the real path:
/usr/local/Cellar/maven/3.2.3/libexec/bin/mvn
Якщо ваша ОС це підтримує, використовуйте:
realpath "./some/dir"
І використовуючи його у змінній:
some_path="$(realpath "./some/dir")"
Що розширить ваш шлях. Протестовано на Ubuntu та CentOS, можливо, недоступне на ваших. Деякі рекомендують readlink, але в документації для readlink сказано:
Примітка. Realpath (1) - найкраща команда, яка використовується для функціонування канонізації.
Якщо люди задаються питанням, чому я цитую свої змінні, це збереження пробілів у контурах. Як робити, realpath some path
це дасть вам два різні результати шляху. Але realpath "some path"
поверне один. Параметри котирування ftw :)
Чи потрібно використовувати виключно bash? Мені потрібно було це зробити, і я набрид від відмінностей між Linux та OS X. Тож я використав PHP для швидкого та брудного рішення.
#!/usr/bin/php <-- or wherever
<?php
{
if($argc!=2)
exit();
$fname=$argv[1];
if(!file_exists($fname))
exit();
echo realpath($fname)."\n";
}
?>
Я знаю, що це не дуже елегантне рішення, але воно працює.