Bash: récupérer le chemin absolu donné relatif
y a-t-il une commande pour récupérer le chemin absolu donné au 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
16 réponses
utiliser:
find $(pwd)/ -type f
pour obtenir tous les fichiers ou
echo $(pwd)/$line
pour afficher le chemin complet (si le chemin relatif est important)
Essayer realpath
.
~ $ sudo apt-get install realpath
~ $ realpath .bashrc
/home/username/.bashrc
La réponse vient de " bash/poissons de commande à imprimer 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 paquet absolu (avec tous les liens symboliques résolus)
#! /bin/sh
echo "$(cd "$(dirname "")"; pwd)/$(basename "")"
UPD des explications
- ce script obtient le chemin relatif comme argument
""
- puis nous obtenons dirname partie de ce chemin (vous pouvez passer soit dir ou fichier à ce script):
dirname ""
- puis nous
cd "$(dirname "")
dans cette dir relative et obtenir le chemin absolu pour elle en exécutantpwd
commande shell - après cela nous ajoutons basename à chemin absolu:
$(basename "")
- comme étape finale nous
echo
it
pour ce que ça vaut, j'ai voté pour la réponse qui a été choisie, mais je voulais partager une solution. L'inconvénient est que C'est Linux seulement - j'ai passé environ 5 minutes à essayer de trouver L'équivalent OSX avant de venir à Stack overflow. Je suis sûr qu'elle est là, cependant.
sous Linux, vous pouvez utiliser readlink -e
en tandem avec dirname
.
$(dirname $(readlink -e ../../../../etc/passwd))
rendements
/etc/
Et puis vous utilisez dirname
sœur, basename
pour obtenir juste
le nom du fichier
$(basename ../../../../../passwd)
rendements
passwd
rassemblez tout..
F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"
rendements
/etc/passwd
vous êtes en sécurité si vous ciblez un répertoire, basename
ne vous retournera rien
et vous finirez avec des doubles slashes dans la sortie finale.
je pense que c'est le plus portable:
abspath() {
cd "$(dirname "")"
printf "%s/%s\n" "$(pwd)" "$(basename "")"
cd "$OLDPWD"
}
il échouera si le chemin n'existe pas.
realpath
est probablement le meilleur
mais ...
la question initiale était très confuse pour commencer, avec un exemple mal lié à la question comme indiqué.
la réponse choisie répond en fait à l'exemple donné, et pas du tout la question est dans le titre. La première commande est cette réponse (est-elle vraiment ? Je doute), et pourrait faire aussi bien sans le '/'. Et je ne vois pas ce que la deuxième commande est faire.
plusieurs questions sont mélangées :
-
changer un chemin relatif en un chemin absolu, quel qu'il soit désigne, probablement rien. ( typiquement, si vous émettez une commande telle que
touch foo/bar
, le le nom de cheminfoo/bar
doit exister pour vous, et peut-être être utilisé dans calcul, avant que le fichier est créé. ) -
il peut y avoir plusieurs chemin absolu qui dénotent le même fichier (ou fichier potentiel), notamment en raison de liens symboliques (liens symboliques) sur le chemin, mais peut-être pour d'autres raisons (d'un appareil peut être monté deux fois en lecture seule). Un peut ou peut ne pas vouloir résoudre explicitement de tels liens symboliques.
-
arriver au bout d'une chaîne de liens symboliques vers un lien non-symétrique nom de fichier ou de. Ceci peut ou ne peut pas donner un nom de chemin absolu, en fonction de comment il est fait. Et l'on peut, ou ne peut pas voulez résoudre dans un chemin absolu.
La commande readlink foo
sans option donne une réponse seulement si son
l'argument foo
est un lien symbolique, et cette réponse est la valeur de la
symbolique. Aucun autre lien 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
fichiers, et en donner un chemin absolu (l'un avec aucun des liens symboliques) à
le fichier indiqué par l'argument.
cela fonctionne très bien pour tout ce qui n'est pas un lien symbolique, bien que l'on pourrait
le désir d'utiliser un chemin absolu sans résoudre l'intermédiaire
liens symboliques 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 sera
encore résoudre tous les liens symboliques sur le chemin absolu de l'argument, mais
que inclura également tous les liens symboliques qui peuvent être rencontrés par
suivant la valeur de l'argument. Vous pourriez ne pas vouloir que si vous avez désiré un
chemin absolu vers l'argument symlink lui-même, plutôt que vers quoi que ce soit
il peut se lier à. Encore une fois, si foo
est un lien symbolique, realpath -s foo
sera
obtenir un chemin absolu sans résoudre les liens symboliques, y compris celui
donné en argument.
sans l'option -s
, realpath
fait à peu près la même chose que
readlink
, sauf pour simple la lecture de la valeur d'un lien, ainsi que plusieurs
d'autres choses. Il n'est tout simplement pas clair pour moi pourquoi readlink
a ses
options, créant apparemment une redondance indésirable avec
realpath
.
explorer le web ne dit pas beaucoup plus, sauf qu'il peut y avoir certaines variations entre les systèmes.
Conclusion: realpath
est la meilleure commande à utiliser, avec le plus
flexibilité, au moins pour l'usage demandé ici.
la réponse D'Eugen n'a pas tout à fait fonctionné pour moi mais cela a fait:
absolute="$(cd $(dirname $file); pwd)/$(basename $file)"
note latérale, votre répertoire de travail actuel n'est pas affecté.
dans le cas de find
, il est probablement plus facile de simplement donner le chemin absolu pour qu'il cherche, par exemple:
find /etc
find `pwd`/subdir_of_current_dir/ -type f
si vous utilisez bash sur Mac OS X qui n'a pas realpath existant ni son readlink peut imprimer le chemin absolu, vous pouvez avoir le choix mais de coder votre propre version pour l'imprimer. Voici mon implémentation:
(pur bash)
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[*]}"
)
}
(utiliser gawk)
abspath_gawk() {
if [[ -n "" ]];then
echo |gawk '{
if(substr("151910920",1,1) != "/"){
path = ENVIRON["PWD"]"/""151910920"
} else path = "151910920"
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
}
(pur 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("151920920")
}
exemple:
$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
ma solution préférée était celle de @EugenKonkov car elle n'impliquait pas la présence d'autres utilitaires (le paquet coreutils).
, Mais il a échoué pour les chemins d'accès relatifs "." et." .", voici donc une version légèrement améliorée traitant ces cas spéciaux.
il échoue toujours si l'utilisateur n'a pas la permission 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=""
if [ "$target" == "." ]; then
echo "$(pwd)"
elif [ "$target" == ".." ]; then
echo "$(dirname "$(pwd)")"
else
echo "$(cd "$(dirname "")"; pwd)/$(basename "")"
fi
}
ce qu'ils ont dit, sauf find $PWD
ou (en bash) find ~+
est un peu plus commode.
similaire à la réponse de @ernest-a, mais sans affecter $OLDPWD
ou définir une nouvelle fonction, vous pourriez tirer un subshell (cd <path>; pwd)
$ pwd
/etc/apache2
$ cd ../cups
$ cd -
/etc/apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups
si le chemin relatif est un chemin de répertoire, alors essayez mine, 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 dans l'absolu, cela fonctionne :
dir=`cd "$dir"`
" cd " fait écho sans changer le répertoire de travail, car exécuté ici dans un sous-shell.
echo "mydir/doc/ mydir/usoe ./mydir/usm" | awk '{ split("151900920",array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'