Czy istnieje polecenie pobrania ścieżki bezwzględnej podanej ścieżką względną?
Na przykład chcę, aby $ line zawierało bezwzględną ścieżkę każdego pliku w katalogu ./etc/
find ./ -type f | while read line; do
echo $line
done
Czy istnieje polecenie pobrania ścieżki bezwzględnej podanej ścieżką względną?
Na przykład chcę, aby $ line zawierało bezwzględną ścieżkę każdego pliku w katalogu ./etc/
find ./ -type f | while read line; do
echo $line
done
Odpowiedzi:
posługiwać się:
find "$(pwd)"/ -type f
aby pobrać wszystkie pliki lub
echo "$(pwd)/$line"
wyświetlić pełną ścieżkę (jeśli ważna jest ścieżka względna)
$(pwd)
zamiast $PWD
? (tak, wiem, że pwd
jest wbudowany)
Spróbuj realpath
.
~ $ sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
Aby uniknąć rozwijania linków symbolicznych, użyj realpath -s
.
Odpowiedź pochodzi z polecenia „ bash / fish polecenie wypisania bezwzględnej ścieżki do pliku ”.
realpath
nie wydaje się być dostępny w systemie Mac (OS X 10.11 „El Capitan”). :-(
realpath
nie wydaje się być również dostępny w CentOS 6
brew install coreutils
przyniesierealpath
realpath
jest już obecny. Nie musiałem go instalować osobno.
realpath
jest , że jest dostępny na Git for Windows (przynajmniej dla mnie).
Jeśli masz zainstalowany pakiet coreutils, możesz ogólnie użyć go readlink -f relative_file_name
w celu odzyskania absolutnego (z rozwiązanymi wszystkimi dowiązaniami symbolicznymi)
brew install coreutils
. Jednak plik wykonywalny jest poprzedzony przez ag:greadlink -f relative_file_name
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
UPD Kilka wyjaśnień
"$1"
dirname "$1"
cd "$(dirname "$1")
przechodzimy do tego względnego katalogu i uzyskujemy do niego ścieżkę bezwzględną, uruchamiając pwd
polecenie powłoki$(basename "$1")
echo
torealpath
lub readlink -f
zrobić. Na przykład nie działa na ścieżkach, w których ostatni składnik jest dowiązaniem symbolicznym.
-P
opcję pwd
polecenia:echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
Głosowałem za wybraną odpowiedzią, ale chciałem podzielić się rozwiązaniem. Wadą jest to, że jest to tylko Linux - spędziłem około 5 minut próbując znaleźć odpowiednik OSX, zanim doszedłem do przepełnienia stosu. Jestem pewien, że tam jest.
W systemie Linux można używać readlink -e
w połączeniu z dirname
.
$(dirname $(readlink -e ../../../../etc/passwd))
plony
/etc/
A potem używasz dirname
siostry ', basename
aby po prostu uzyskać nazwę pliku
$(basename ../../../../../passwd)
plony
passwd
Poskładać wszystko do kupy..
F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"
plony
/etc/passwd
Jesteś bezpieczny, jeśli celujesz w katalog, basename
nic nie zwróci, a skończysz z podwójnymi ukośnikami w ostatecznym wyniku.
dirname
, readlink
, i basename
. To pomogło mi uzyskać absolutną ścieżkę dowiązania symbolicznego, a nie jego cel.
/home/GKFX
i piszę touch newfile
, to zanim naciśnę klawisz Enter, możesz dojść do wniosku, że mam na myśli „create / home / GKFX / newfile”, co jest bezwzględną ścieżką do pliku, który jeszcze nie istnieje.
Myślę, że jest to najbardziej przenośny:
abspath() {
cd "$(dirname "$1")"
printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
cd "$OLDPWD"
}
Nie powiedzie się, jeśli ścieżka nie istnieje.
dirname
jest podstawowym narzędziem GNU, nie jest wspólne dla wszystkich unixenów, jak sądzę.
dirname
to standardowe narzędzie POSIX, patrz tutaj: pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html
${1##*/}
od jednego dnia, a teraz, kiedy zastąpiłem ten kosz basename "$1"
, wydaje się, że w końcu poprawnie obsługują ścieżki kończące się na /.
../..
realpath
jest prawdopodobnie najlepszy
Ale ...
Początkowe pytanie było bardzo zagmatwane na początku, z przykładem słabo powiązanym z zadanym pytaniem.
Wybrana odpowiedź w rzeczywistości odpowiada na podany przykład, a nie na pytanie w tytule. Pierwsza komenda to odpowiedź (czy naprawdę? Wątpię) i równie dobrze mogłaby działać bez znaku „/”. I nie widzę, co robi drugie polecenie.
Kilka problemów jest mieszanych:
zmiana względnej ścieżki na absolutną, cokolwiek by to oznaczało, prawdopodobnie nic. ( Zazwyczaj, jeśli wydasz takie polecenie, jak touch foo/bar
nazwa ścieżki, foo/bar
musi istnieć dla Ciebie i prawdopodobnie zostać użyta w obliczeniach, zanim plik zostanie faktycznie utworzony ).
może istnieć kilka bezwzględnych nazw ścieżek, które oznaczają ten sam plik (lub potencjalny plik), w szczególności z powodu dowiązań symbolicznych (dowiązań symbolicznych) na ścieżce, ale prawdopodobnie z innych powodów (urządzenie może być zamontowane dwa razy jako tylko do odczytu). Można lub nie chcieć rozwiązywać jawności takich dowiązań symbolicznych.
dotarcie do końca łańcucha dowiązań symbolicznych do pliku lub nazwy niebędącej dowiązaniem symbolicznym. To może, ale nie musi, dać absolutną nazwę ścieżki, w zależności od tego, jak jest to zrobione. I można, ale nie trzeba, przekształcić to w absolutną ścieżkę.
Polecenie readlink foo
bez opcji daje odpowiedź tylko wtedy, gdy jego argumentfoo
jest dowiązanie symboliczne, a ta odpowiedź jest wartością tego dowiązania symbolicznego. Żaden inny link nie jest używany. Odpowiedzią może być ścieżka względna: cokolwiek było wartością argumentu dowiązania symbolicznego.
Jednak, readlink
ma opcje (-f -e lub -m), które będą działać dla wszystkich plików i podadzą jedną bezwzględną ścieżkę dostępu (tę bez dowiązań symbolicznych) do pliku faktycznie oznaczonego przez argument.
Działa to dobrze w przypadku wszystkiego, co nie jest dowiązaniem symbolicznym, chociaż można chcieć użyć bezwzględnej nazwy ścieżki bez rozwiązywania pośrednich dowiązań symbolicznych na ścieżce. Odbywa się to za pomocą poleceniarealpath -s foo
W przypadku argumentu dowiązania symbolicznego, readlink
z jego opcjami ponownie rozwiążemy wszystkie dowiązania symboliczne na bezwzględnej ścieżce do argumentu, ale będzie to również obejmować wszystkie dowiązania symboliczne, które można napotkać, podążając za wartością argumentu. Możesz tego nie chcieć, jeśli chcesz mieć bezwzględną ścieżkę do samego dowodu symbolicznego argumentu, a nie do tego, do czego może ono prowadzić. Ponownie, jeśli foo
jest dowiązaniem symbolicznym, realpath -s foo
otrzyma ścieżkę bezwzględną bez rozpoznawania dowiązań symbolicznych, w tym podanego jako argument.
Bez tej -s
opcji realpath
robi to samo, co
readlink
poza zwykłym odczytem wartości linku, a także kilkoma innymi rzeczami. Po prostu nie jest dla mnie jasne, dlaczego readlink
ma swoje opcje, stwarzając pozornie niepożądaną nadmiarowość
realpath
.
Eksploracja sieci nie mówi nic więcej, z wyjątkiem tego, że mogą występować pewne różnice między systemami.
Wniosek: realpath
to najlepsza komenda do użycia, z największą elastycznością, przynajmniej do użycia tutaj wymaganego.
Moim ulubionym rozwiązaniem było to przez @EugenKonkov ponieważ nie sugerować obecność innych mediów (pakiet coreutils).
Ale zawiodło dla ścieżek względnych "." i „..”, więc tutaj jest nieco ulepszona wersja obsługująca te specjalne przypadki.
cd
Jednak nadal kończy się niepowodzeniem, jeśli użytkownik nie ma uprawnień do dostępu do katalogu nadrzędnego ścieżki względnej.
#! /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
}
Odpowiedź Eugena nie do końca mi odpowiadała, ale tak się stało:
absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"
Uwaga dodatkowa, twój bieżący katalog roboczy pozostaje niezmieniony.
Najlepsze rozwiązanie, imho, to to zamieszczone tutaj: https://stackoverflow.com/a/3373298/9724628 .
Wymaga Pythona do działania, ale wydaje się, że obejmuje wszystkie lub większość przypadków skrajnych i jest bardzo przenośnym rozwiązaniem.
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
Jeśli używasz bash w systemie Mac OS X, który ani nie ma realpath, ani jego readlink nie może wydrukować bezwzględnej ścieżki, możesz mieć wybór i musisz zakodować własną wersję, aby ją wydrukować. Oto moja realizacja:
(czysty bash)
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[*]}"
)
}
(użyj 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
}
(czysty 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)
}
przykład:
$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
Jeśli ścieżka względna jest ścieżką do katalogu, spróbuj mojej, powinna być najlepsza:
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") } }'
Ulepszenie do raczej ładnej wersji @ ernest-a:
absolute_path() {
cd "$(dirname "$1")"
case $(basename $1) in
..) echo "$(dirname $(pwd))";;
.) echo "$(pwd)";;
*) echo "$(pwd)/$(basename $1)";;
esac
}
Rozwiązanie to poprawnie rozwiązuje przypadek, w którym znajduje się ostatni element ścieżki ..
, w którym to przypadku odpowiedź "$(pwd)/$(basename "$1")"
in @ ernest-a pojawi się jako accurate_sub_path/spurious_subdirectory/..
.
Jeśli chcesz przekształcić zmienną zawierającą ścieżkę względną w ścieżkę bezwzględną, działa to:
dir=`cd "$dir"`
„cd” powtarza echo bez zmiany katalogu roboczego, ponieważ jest wykonywany tutaj w powłoce podrzędnej.
dir=`cd ".."` && echo $dir
Jest to rozwiązanie łańcuchowe od wszystkich innych, na przykład w przypadku realpath
niepowodzenia, ponieważ nie jest zainstalowane lub kończy się z kodem błędu, wówczas podejmowane są próby rozwiązania następnego, dopóki nie uzyska właściwej ścieżki.
#!/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")" "${?}"
Możesz użyć podstawienia ciągu bash dla dowolnej ścieżki względnej $ line:
line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line
Podstawowe podstawianie początku ciągu jest zgodne ze wzorem
$ {string / # substring / replace},
który jest dobrze omówiony tutaj: https://www.tldp.org/LDP/abs/html/string-manipulation.html
\
Charakter neguje /
, gdy chcemy, aby być częścią łańcucha, które Znajdź / Zamień.
Nie mogłem znaleźć rozwiązania, które byłoby zgrabnie przenośne między Mac OS Catalina, Ubuntu 16 i Centos 7, więc zdecydowałem się to zrobić z wbudowanym Pythonem i działało dobrze dla moich skryptów bash.
to_abs_path() {
python -c "import os; print os.path.abspath('$1')"
}
to_abs_path "/some_path/../secrets"