Göreli yol verildiğinde mutlak yolu almak için bir komut var mı?
Örneğin $ satır dir her dosyanın mutlak yolunu içeren istiyorum ./etc/
find ./ -type f | while read line; do
echo $line
done
Göreli yol verildiğinde mutlak yolu almak için bir komut var mı?
Örneğin $ satır dir her dosyanın mutlak yolunu içeren istiyorum ./etc/
find ./ -type f | while read line; do
echo $line
done
Yanıtlar:
kullanın:
find "$(pwd)"/ -type f
tüm dosyaları almak için veya
echo "$(pwd)/$line"
tam yolu görüntülemek için (göreli yol önemliyse)
$(pwd)
yerine kullanılır $PWD
? (evet, pwd
yerleşik olduğunu biliyorum )
Deneyin realpath
.
~ $ sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
Simgelerin genişlemesini önlemek için kullanın realpath -s
.
Yanıt " bir dosyaya mutlak yol yazdırmak için bash / fish komutundan " gelir.
realpath
Mac'te mevcut görünmüyor (OS X 10.11 "El Capitan"). :-(
realpath
CentOS 6'da da mevcut görünmüyor
brew install coreutils
getirecekrealpath
realpath
zaten var. Ayrı olarak kurmak zorunda değildim.
realpath
Windows için Git'te kullanılabilir (en azından benim için).
Eğer coreutils paketini kurduysanız, genellikle readlink -f relative_file_name
mutlak olanı almak için kullanabilirsiniz (tüm semboller çözülmüş olarak)
brew install coreutils
. Ancak yürütülebilir ag tarafından eklenir:greadlink -f relative_file_name
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
UPD Bazı açıklamalar
"$1"
dirname "$1"
cd "$(dirname "$1")
bu göreceli dir içine ve pwd
kabuk komutunu çalıştırarak bunun için mutlak yol olsun$(basename "$1")
echo
onurealpath
veya readlink -f
yapmaya eşdeğer değildir . Örneğin, son bileşenin bir sembolik bağlantı olduğu yollarda çalışmaz.
-P
seçeneği sunabilirsiniz pwd
:echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
Değeri için, alınan cevaba oy verdim, ancak bir çözümü paylaşmak istedim. Dezavantajı, sadece Linux - Stack overflow gelmeden önce OSX eşdeğerini bulmak için yaklaşık 5 dakika geçirdim. Eminim orada olsa.
Linux'ta readlink -e
birlikte kullanabilirsiniz dirname
.
$(dirname $(readlink -e ../../../../etc/passwd))
verim
/etc/
Ve sonra dosya adını almak için dirname
kız kardeşini kullanıyorsunbasename
$(basename ../../../../../passwd)
verim
passwd
Hepsini bir araya getirmek..
F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"
verim
/etc/passwd
Bir dizini hedefliyorsanız güvende olursunuz, basename
hiçbir şey döndürmez ve son çıkışta çift eğik çizgi elde edersiniz.
dirname
, readlink
ve basename
. Bu, hedefine değil, sembolik bir bağlantının mutlak yolunu elde etmeme yardımcı oldu.
/home/GKFX
ben yazın touch newfile
ben girmek basmadan önce, sonra ne demek olduğunu işe yarayabilir, "oluşturmak / home / SLFS / yenidosya", henüz var olmayan bir dosyaya mutlak bir yol olduğu.
Bu en taşınabilir olduğunu düşünüyorum:
abspath() {
cd "$(dirname "$1")"
printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
cd "$OLDPWD"
}
Yol mevcut değilse başarısız olur.
dirname
, bir GNU çekirdek yardımcı programdır, inanıyorum tüm unixen için ortak değildir.
dirname
bir POSIX standart yardımcı programıdır, buraya bakın: pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html
${1##*/}
şimdi bir gün için kullanılan sürümü düzeltmek için çalışıyorum , ve şimdi ben basename "$1"
onunla o çöp yerine nihayet sonunda / yollarını düzgün görünüyor gibi görünüyor.
../..
realpath
muhtemelen en iyisi
Fakat ...
İlk soru başlangıçta çok karışıktı, belirtildiği gibi soruyla zayıf ilişkili bir örnek vardı.
Seçilen cevap aslında başlıktaki soruya değil, verilen örneğe cevap verir. İlk komut bu cevaptır (gerçekten mi? Şüphe ediyorum) ve '/' olmadan da yapabilirdi. İkinci komutun ne yaptığını göremiyorum.
Çeşitli konular karışık:
göreceli bir yol adını mutlak bir adla değiştirmek, ne anlama geliyorsa, muhtemelen hiçbir şey. ( Genellikle, böyle bir komut verirseniz touch foo/bar
, yol adının foo/bar
sizin için var olması ve muhtemelen dosya oluşturulmadan önce hesaplamada kullanılması gerekir. )
özellikle yoldaki sembolik bağlantılar (sembolik bağlantılar) nedeniyle, ancak muhtemelen başka nedenlerle (bir aygıt salt okunur olarak iki kez bağlanabilir) nedeniyle aynı dosyayı (veya potansiyel dosyayı) gösteren birkaç mutlak yol adı olabilir. Bu gibi sembolikliklerin çözümlenmesi istenebilir veya edilmeyebilir.
sembolik olmayan bir dosya veya isme sembolik bağlar zincirinin sonuna ulaşmak. Bu, nasıl yapıldığına bağlı olarak mutlak bir yol adı verebilir veya vermeyebilir. Ve kişi bunu mutlak bir yol adına dönüştürmek isteyebilir veya istemeyebilir.
readlink foo
Seçenek içermeyen komut , yalnızca bağımsız değişkeni foo
sembolik bir bağlantıysa ve bu yanıt bu sembolik bağlantının değeri ise bir yanıt verir . Başka hiçbir bağlantı izlenmez. Cevap göreceli bir yol olabilir: symlink argümanının değeri neydi?
Bununla birlikte, readlink
tüm dosyalar için çalışacak ve argüman tarafından belirtilen dosyaya bir mutlak yol adı (sembolik olmayan) verecek seçenekler (-f -e veya -m) vardır.
Bu, bir sembolik olmayan herhangi bir şey için iyi çalışır, ancak yoldaki ara simgeleri çözmeden mutlak bir yol adı kullanmak isteyebilir. Bu komut tarafından yapılırrealpath -s foo
Bir symlink argümanı durumunda readlink
, seçenekleri ile argümanın mutlak yolundaki tüm semboller tekrar çözülür, ancak bu, argüman değerini izleyerek karşılaşılabilecek tüm sembolik bağlantıları da içerir. Symlink argümanının kendisine giden mutlak bir yol istiyorsanız, link verebileceklerinden ziyade bunu istemeyebilirsiniz. Yine, foo
bir symlink ise , realpath -s foo
argüman olarak verilenler de dahil olmak üzere, sembolik bağlantıları çözmeden mutlak bir yol alacaktır.
-s
Seçenek olmadan, sadece bir bağlantının değerini ve diğer bazı şeyleri okumak dışında realpath
hemen hemen aynı
readlink
şeyi yapar. readlink
Görünüşe göre, istenmeyen bir artıklık yaratan seçeneklerinin neden olduğu
açık değilrealpath
.
Web'i keşfetmek çok daha fazla şey söylemez, ancak sistemler arasında bazı farklılıklar olabilir.
Sonuç: realpath
en azından burada istenen kullanım için en esnek ve en esnek komut kullanmaktır.
Benim favori çözümdü biri diğer araçlardan varlığını (coreutils paketi) anlamına gelmediğini çünkü @EugenKonkov tarafından.
Ancak göreli yollar "" için başarısız oldu. ve "..", işte bu özel durumları ele alan biraz geliştirilmiş bir versiyon.
Yine de, kullanıcı cd
göreli yolun üst dizinine girme iznine sahip değilse başarısız olur .
#! /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
}
Eugen'in cevabı benim için pek işe yaramadı ama bu işe yaradı:
absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"
Yan not, geçerli çalışma dizininiz etkilenmez.
En iyi çözüm, imho, burada yayınlanan çözümdür: https://stackoverflow.com/a/3373298/9724628 .
Çalışması için python gerektiriyor, ancak kenar kasalarının tümünü veya çoğunu kapsıyor ve çok taşınabilir bir çözüm gibi görünüyor.
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
Gerçek yol bulunmayan veya okuma bağlantısı mutlak yolu yazamayan Mac OS X'te bash kullanıyorsanız , yazdırmak için kendi sürümünüzü kodlamaktan başka seçeneğiniz olabilir. İşte benim uygulama:
(saf 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[*]}"
)
}
(gawk kullanın)
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
}
(saf 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)
}
misal:
$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
Göreli yol bir dizin yoluysa, benimkini deneyin, en iyisi olmalıdır:
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'nın oldukça güzel versiyonunda bir gelişme:
absolute_path() {
cd "$(dirname "$1")"
case $(basename $1) in
..) echo "$(dirname $(pwd))";;
.) echo "$(pwd)";;
*) echo "$(pwd)/$(basename $1)";;
esac
}
Bu, yolun son öğesinin olduğu durumla doğru bir şekilde ilgilenir ..
, bu durumda "$(pwd)/$(basename "$1")"
in @ ernest-a'nın cevabı olarak gelir accurate_sub_path/spurious_subdirectory/..
.
Göreli yol içeren bir değişkeni mutlak olana dönüştürmek istiyorsanız, bu işe yarar:
dir=`cd "$dir"`
"cd" çalışma dizinini değiştirmeden yankılanır, çünkü burada bir alt kabukta yürütülür.
dir=`cd ".."` && echo $dir
Bu, realpath
yüklü olmadığı veya hata koduyla çıktığı için başarısız olduğunda, diğerlerinden zincirlenmiş bir çözümdür , o zaman bir sonraki çözüm yolu doğru alana kadar denenir.
#!/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")" "${?}"
Herhangi bir göreli yol $ satırı için bash dizesi yerine kullanabilirsiniz:
line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line
Temel dize ön ikamesi
, burada iyi tartışılan
$ {string / # substring / replacement} formülünü izler
: https://www.tldp.org/LDP/abs/html/string-manipulation.html
\
Karakter olumsuzlar /
biz biz / bulmak yerine İpin parçası olmak istediğinizde.
Mac OS Catalina, Ubuntu 16 ve Centos 7 arasında düzgün taşınabilir bir çözüm bulamadım, bu yüzden python inline ile yapmaya karar verdim ve bash scriptlerim için iyi çalıştı.
to_abs_path() {
python -c "import os; print os.path.abspath('$1')"
}
to_abs_path "/some_path/../secrets"