Existe-t-il une commande permettant de récupérer le chemin absolu étant donné le chemin relatif?
Par exemple, je veux que $ line contienne le chemin absolu de chaque fichier dans dir ./etc/
find ./ -type f | while read line; do
echo $line
done
utilisation:
find $(pwd)/ -type f
pour obtenir tous les fichiers ou
echo $(pwd)/$line
pour afficher le chemin complet (si le chemin relatif est important)
Essayez realpath
.
~ $ Sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
Pour éviter de développer des liens symboliques, utilisez realpath -s
.
La réponse provient de la commande " bash/fish" pour imprimer le chemin absolu vers un fichier ".
Si vous avez le paquet coreutils installé, vous pouvez généralement utiliser readlink -f relative_file_name
pour récupérer le fichier absolu (avec tous les liens symboliques résolus)
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
UPDQuelques explications
"$1"
dirname "$1"
cd "$(dirname "$1")
dans ce répertoire relatif et obtenons son chemin absolu en exécutant la commande pwd
Shell$(basename "$1")
echo
ilPour ce que ça vaut, j'ai voté pour la réponse choisie, mais je voulais partager une solution. L’inconvénient est qu’il s’agit uniquement de Linux - j’ai passé environ 5 minutes à essayer de trouver l’équivalent OSX avant d’aborder le débordement de pile. Je suis sûr que c'est là-bas cependant.
Sous Linux, vous pouvez utiliser readlink -e
en tandem avec dirname
.
$(dirname $(readlink -e ../../../../etc/passwd))
les rendements
/etc/
Et vous utilisez ensuite la soeur de dirname
, basename
pour obtenir simplement Le nom du fichier.
$(basename ../../../../../passwd)
les rendements
passwd
Mets le tout ensemble..
F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"
les rendements
/etc/passwd
Vous êtes en sécurité si vous ciblez un répertoire, basename
ne renverra rien .__ et vous obtiendrez simplement une double barre oblique dans la sortie finale.
Je pense que c'est le plus portable:
abspath() {
cd "$(dirname "$1")"
printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
cd "$OLDPWD"
}
Cela échouera si le chemin n'existe pas.
realpath
est probablement le meilleur
Mais ...
La question initiale était très confuse au départ, avec un exemple mal lié à la question telle que formulée.
La réponse sélectionnée répond effectivement à l'exemple donné, et pas du tout À la question dans le titre. La première commande est cette réponse (est-ce Vraiment? Je doute), et pourrait faire aussi bien sans le '/'. Et je ne parviens pas à voir Ce que fait la deuxième commande.
Plusieurs problèmes sont mélangés:
changer un nom de chemin relatif en un nom absolu, peu importe ce que cela signifie dénote, éventuellement rien . ( Généralement, si vous exécutez une commande telle que touch foo/bar
, le chemin. foo/bar
doit exister pour vous et éventuellement être utilisé dans le calcul, avant que le fichier ne soit réellement créé )
il peut y avoir plusieurs chemins absolus indiquant le même fichier .__ (ou fichier potentiel), notamment en raison de liens symboliques (liens symboliques) sur le chemin, mais éventuellement pour d'autres raisons (un périphérique peut être monté deux fois en lecture seule). On peut ou non vouloir résoudre Explicitement de tels liens symboliques.
arriver à la fin d'une chaîne de liens symboliques vers un fichier ou un nom non symlink Cela peut ou peut ne pas donner un chemin absolu, Selon la façon dont cela est fait. Et on peut ou ne peut pas vouloir Le résoudre en un chemin absolu.
La commande readlink foo
sans option ne donne une réponse que si son Argument foo
est un lien symbolique et que cette réponse est la valeur de ce Symlink. Aucun autre lien n'est suivi. La réponse peut être un chemin relatif: Quelle que soit la valeur de l’argument du lien symbolique.
Cependant, readlink
a des options (-f -e ou -m) qui fonctionneront pour tous les fichiers Et donneront un chemin absolu (celui sans liens symboliques) à Le fichier désigné par l'argument.
Cela fonctionne bien pour tout ce qui n’est pas un lien symbolique, bien que l’on puisse souhaiter utiliser un chemin absolu sans résoudre les liens symboliques intermédiaires sur le chemin. Ceci est fait par la commande realpath -s foo
Dans le cas d'un argument de lien symbolique, readlink
avec ses options résoudra à nouveau tous les liens symboliques sur le chemin absolu de l'argument, mais , Qui inclura également tous les liens symboliques pouvant être rencontrés par Après la valeur de l'argument . Si vous souhaitez un chemin Absolu vers l'argument symlink plutôt que vers quoi que ce soit, vous ne voudrez peut-être pas le faire. De nouveau, si foo
est un lien symbolique, realpath -s foo
obtiendra un chemin absolu sans résoudre les liens symboliques, y compris celui qui est donné comme argument.
Sans l'option -s
, realpath
fait à peu près la même chose que readlink
, à l'exception de la simple lecture de la valeur d'un lien, ainsi que de plusieurs autres choses. Je ne comprends tout simplement pas pourquoi readlink
a ses options , Ce qui crée apparemment une redondance indésirable avec realpath
.
Explorer le Web n’en dit pas beaucoup plus, sauf qu’il peut y avoir quelques variations entre les systèmes.
Conclusion: realpath
est la meilleure commande à utiliser, avec la plus grande souplesse, au moins pour l’utilisation demandée ici.
La réponse d'Eugen n'a pas fonctionné pour moi, mais cela a fonctionné:
absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"
Remarque secondaire, votre répertoire de travail actuel n'est pas affecté.
Ma solution préférée était celle de @EugenKonkov car elle n’impliquait pas la présence d’autres utilitaires (le package coreutils).
Mais cela a échoué pour les chemins relatifs "." et "..", voici donc une version légèrement améliorée gérant ces cas particuliers.
Il échoue quand même si l'utilisateur n'a pas l'autorisation de cd
dans le répertoire parent du chemin relatif, cependant.
#! /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
}
Si vous utilisez bash sur Mac OS X alors que ni realpath ni readlink ne peuvent imprimer le chemin absolu, vous pouvez choisir de coder votre propre version pour l’imprimer .. ma mise en oeuvre:
(pure 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[*]}"
)
}
(utiliser 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
}
(pure 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)
}
exemple:
$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
Dans le cas de find
, il est probablement plus facile de simplement donner le chemin absolu dans lequel effectuer la recherche, par exemple:
find /etc
find `pwd`/subdir_of_current_dir/ -type f
Il s'agit d'une solution chaînée de toutes les autres, par exemple, lorsque realpath
échoue, soit parce qu'il n'est pas installé, soit parce qu'il se termine avec un code d'erreur, puis la solution suivante est tentée jusqu'à ce que le chemin d'accès soit correct.
#!/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")" "${?}"
echo "mydir/doc/ mydir/usoe ./mydir/usm" | awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'
Similaire à la réponse de @ ernest-a mais sans affecter $OLDPWD
ni définir une nouvelle fonction, vous pouvez déclencher un sous-shell (cd <path>; pwd)
$ pwd
/etc/Apache2
$ cd ../cups
$ cd -
/etc/Apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups
La meilleure solution, à mon humble avis, est celle publiée ici: https://stackoverflow.com/a/3373298/9724628 .
Python est nécessaire pour fonctionner, mais il semble couvrir la totalité ou la plupart des cas Edge et constituer une solution très portable.
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
Si le chemin relatif est un chemin de répertoire, alors essayez le mien, ça devrait être le meilleur:
absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)
echo $absPath
Si vous voulez transformer une variable contenant un chemin relatif en un chemin absolu, ceci fonctionne:
dir=`cd "$dir"`
"cd" résonne sans changer le répertoire de travail, car exécuté ici dans un sous-shell.
Ce qu’ils ont dit, sauf que find $PWD
ou (en bash) find ~+
est un peu plus pratique.