วิธีการดึงข้อมูลพา ธ สัมบูรณ์ที่สัมพันธ์กัน


159

มีคำสั่งให้ดึงเส้นทางสัมบูรณ์ที่กำหนดเส้นทางสัมพัทธ์หรือไม่?

ตัวอย่างเช่นฉันต้องการ $ line มีเส้นทางที่แน่นอนของแต่ละไฟล์ใน dir ./etc/

find ./ -type f | while read line; do
   echo $line
done


1
ไม่ใช่ Stright ที่ซ้ำกัน แต่คล้ายกัน
mpapis


ทางออกที่ดีกว่าโซลูชันใด ๆ ที่อยู่ในรายการอยู่ที่นี่วิธีการแปลงค่าเส้นทางสัมพัทธ์กับเส้นทางแบบสัมบูรณ์ - ยูนิกซ์
Daniel Genin

คำตอบ:


66

ใช้:

find "$(pwd)"/ -type f

เพื่อรับไฟล์ทั้งหมดหรือ

echo "$(pwd)/$line"

เพื่อแสดงเส้นทางแบบเต็ม (ถ้าเส้นทางสัมพันธ์สัมพันธ์กับ)


2
จะทำอย่างไรถ้าฉันระบุเส้นทางที่สัมพันธ์กันในการค้นหา ??
nubme

17
จากนั้นดูลิงก์ในความคิดเห็นสำหรับคำถามของคุณวิธีที่ดีที่สุดน่าจะเป็น 'readlink -f $ line'
mpapis

3
ทำไมใช้$(pwd)ในสถานที่ของ$PWD? (ใช่ฉันรู้ว่าpwdเป็นตัว)
Adam Katz

178

ลองrealpathดู

~ $ sudo apt-get install realpath  # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc

เพื่อหลีกเลี่ยงการขยาย symlinks realpath -sใช้

คำตอบมาจาก " คำสั่ง bash / fish เพื่อพิมพ์พา ธ สัมบูรณ์ไปยังไฟล์ "


11
realpathดูเหมือนจะไม่มีใน Mac (OS X 10.11 "El Capitan") :-(
Laryx Decidua

realpathดูเหมือนจะไม่สามารถใช้งานบน CentOS 6 ได้เช่นกัน
user5359531

6
บน osx brew install coreutilsจะนำเข้าrealpath
Kevin Chen

ใน Ubuntu 18.04 ของฉันrealpathมีอยู่แล้ว ฉันไม่ต้องติดตั้งแยกต่างหาก
คิวเมนตัส

น่าแปลกที่realpathมีใน Git สำหรับ Windows (สำหรับฉันอย่างน้อย)
Andrew Keeton

104

หากคุณมีการติดตั้งแพ็คเกจ coreutils โดยทั่วไปคุณสามารถใช้readlink -f relative_file_nameเพื่อเรียกคืนหนึ่งแน่นอน (ด้วย symlink ทั้งหมดได้รับการแก้ไข)


3
พฤติกรรมนี้แตกต่างจากสิ่งที่ผู้ใช้ถามเล็กน้อยมันจะติดตามและแก้ไขการเชื่อมโยงแบบเรียกซ้ำที่ใดก็ได้ในเส้นทาง คุณอาจไม่ต้องการในบางกรณี
ffledgling

1
@BradPeabody นี้จะทำงานใน Mac หากคุณติดตั้ง coreutils จาก brew install coreutilshomebrew อย่างไรก็ตามไฟล์ปฏิบัติการนั้นได้รับการเสริมโดย ag:greadlink -f relative_file_name
Miguel Isla

2
โปรดสังเกตว่าหน้าคู่มือของ readlink (1) มีประโยคแรกของคำอธิบาย: "หมายเหตุ realpath (1) เป็นคำสั่งที่ต้องการเพื่อใช้สำหรับฟังก์ชั่นการทำให้เป็นมาตรฐาน
josch

1
คุณสามารถใช้ -e แทน -f เพื่อตรวจสอบว่ามีไฟล์ / ไดเร็กตอรี่หรือไม่
Iceman

69
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"

UPDคำอธิบายบางอย่าง

  1. สคริปต์นี้รับเส้นทางสัมพัทธ์เป็นอาร์กิวเมนต์ "$1"
  2. จากนั้นเราจะได้รับส่วนdirnameของเส้นทางนั้น (คุณสามารถส่ง dir หรือไฟล์ไปที่สคริปต์นี้):dirname "$1"
  3. จากนั้นเราcd "$(dirname "$1")เข้าสู่ dir สัมพัทธ์นี้และรับเส้นทางสัมบูรณ์โดยเรียกใช้pwdคำสั่งเชลล์
  4. หลังจากนั้นเราผนวกbasenameเส้นทางแน่นอน:$(basename "$1")
  5. ในฐานะที่เป็นขั้นตอนสุดท้ายเราechoมัน

8
คำตอบนี้ใช้ Bash idiom ที่ดีที่สุด
Rondo

2
readlink เป็นโซลูชันที่ง่ายสำหรับ linux แต่โซลูชันนี้ใช้ได้กับ OSX เช่นกันดังนั้น +1
thetoolman

1
สคริปต์นี้ไม่เทียบเท่ากับสิ่งที่ทำrealpathหรือ readlink -fตัวอย่างเช่นมันไม่ทำงานบนเส้นทางที่องค์ประกอบสุดท้ายคือ symlink
josch

2
@josch: คำถามไม่ได้เกี่ยวกับการแก้ไข symlink แต่ถ้าคุณต้องการทำเช่นนั้นคุณสามารถให้-Pตัวเลือกในการpwdบังคับบัญชา:echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
Eugen Konkov

4
ฉันชอบคำตอบ แต่ใช้งานได้หากผู้ใช้ได้รับอนุญาตให้ cd ลงในไดเรกทอรี สิ่งนี้อาจไม่สามารถทำได้
Matthias B

34

สำหรับสิ่งที่คุ้มค่าฉันลงคะแนนให้กับคำตอบที่เลือก แต่ต้องการแบ่งปันวิธีแก้ปัญหา ข้อเสียคือเป็นลินุกซ์เท่านั้น - ฉันใช้เวลาประมาณ 5 นาทีในการหาค่า OSX ที่เทียบเท่ากันก่อนที่จะมาล้นสแต็ค ฉันแน่ใจว่ามันออกมี

บน Linux คุณสามารถใช้ควบคู่กับreadlink -edirname

$(dirname $(readlink -e ../../../../etc/passwd))

อัตราผลตอบแทน

/etc/

และจากนั้นคุณใช้dirnameน้องสาวของbasenameเพื่อให้ได้ชื่อไฟล์

$(basename ../../../../../passwd)

อัตราผลตอบแทน

passwd

นำมารวมกัน ..

F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"

อัตราผลตอบแทน

/etc/passwd

คุณปลอดภัยหากคุณกำหนดเป้าหมายไดเรกทอรีbasenameจะไม่คืนสิ่งใดเลยและคุณก็จะได้เครื่องหมายทับสองครั้งในผลลัพธ์สุดท้าย


รายการที่ยอดเยี่ยมด้วยdirname, และreadlink basenameนั่นช่วยให้ฉันได้เส้นทางที่สมบูรณ์ของลิงก์สัญลักษณ์ไม่ใช่เป้าหมาย
kevinarpe

ไม่ทำงานเมื่อคุณต้องการกลับเส้นทางไปยังลิงก์สัญลักษณ์ (ซึ่งฉันเพิ่งเกิดขึ้นต้องทำ ... )
Tomáš Zato - Reinstate Monica

คุณจะหาเส้นทางที่แน่นอนไปยังเส้นทางที่ไม่มีอยู่ได้อย่างไร?
synthesizerpatel

@synthesizerpatel ค่อนข้างง่ายฉันจะคิด ถ้าฉันอยู่ใน/home/GKFXและฉันพิมพ์touch newfileแล้วก่อนที่ฉันจะกด Enter คุณสามารถทำงานได้ว่าฉันหมายถึง "create / home / GKFX / newfile" ซึ่งเป็นเส้นทางที่แน่นอนไปยังไฟล์ที่ยังไม่มีอยู่
GKFX

25

ฉันคิดว่านี่เป็นอุปกรณ์พกพาที่ดีที่สุด:

abspath() {                                               
    cd "$(dirname "$1")"
    printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
    cd "$OLDPWD"
}

มันจะล้มเหลวหากเส้นทางไม่มีอยู่


3
ไม่จำเป็นต้องย้อนกลับมาอีกครั้ง ดูstackoverflow.com/a/21188136/1504556 คำตอบของคุณคือคำตอบที่ดีที่สุดในหน้านี้ IMHO สำหรับผู้ที่สนใจลิงค์จะให้คำอธิบายว่าทำไมโซลูชั่นนี้จึงใช้ได้
เตอร์

นี่ไม่ใช่แบบพกพามากdirnameเป็น GNU core ยูทิลิตี้ไม่ใช่เรื่องธรรมดาสำหรับยูนิกซ์ทั้งหมดที่ฉันเชื่อ
einpoklum

@einpoklum dirnameเป็นยูทิลิตี้มาตรฐาน POSIX ดูที่นี่: pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html
Ernest A

โอ้พระเจ้าขอบคุณ ฉันพยายามแก้ไขเวอร์ชันที่ใช้งาน${1##*/}มาหนึ่งวันแล้วและตอนนี้ฉันแทนที่ถังขยะด้วยbasename "$1"ดูเหมือนว่าในที่สุดจะจัดการเส้นทางที่ถูกต้องใน /
l3l_aze

NB, สิ่งนี้ไม่ได้ทำสิ่งที่ถูกต้องกับเส้นทางที่ลงท้ายด้วย../..
อเล็กซ์โคเวนทรี

16

realpath น่าจะดีที่สุด

แต่ ...

คำถามเริ่มต้นสับสนมากเมื่อเริ่มต้นด้วยตัวอย่างที่เกี่ยวข้องกับคำถามตามที่ระบุไว้ไม่ดี

คำตอบที่เลือกจริงตอบตัวอย่างที่กำหนดและไม่ใช่คำถามในชื่อ คำสั่งแรกคือคำตอบนั้น (จริงหรือไม่ฉันสงสัย) และสามารถทำได้โดยไม่ต้องใช้ '/' และฉันไม่เห็นว่าคำสั่งที่สองกำลังทำอะไรอยู่

มีหลายประเด็นที่หลากหลาย:

  • การเปลี่ยนชื่อพา ธ ที่สัมพันธ์กันให้เป็นชื่อที่แน่นอนไม่ว่ามันจะเป็นอะไร ( โดยทั่วไปหากคุณออกคำสั่งเช่นtouch foo/barชื่อพา ธfoo/barต้องมีอยู่สำหรับคุณและอาจใช้ในการคำนวณก่อนที่ไฟล์จะถูกสร้างขึ้นจริง )

  • อาจมีชื่อพา ธ สัมบูรณ์หลายอันที่แสดงถึงไฟล์เดียวกัน (หรือไฟล์ที่อาจเป็นไปได้) โดยเฉพาะอย่างยิ่งเนื่องจากลิงก์สัญลักษณ์ (symlinks) บนพา ธ แต่อาจเป็นเพราะเหตุผลอื่น (อุปกรณ์อาจถูกเมาท์สองครั้งเป็นแบบอ่านอย่างเดียว) หนึ่งอาจหรืออาจไม่ต้องการแก้ไขข้อบกพร่องดังกล่าว symlink

  • ไปที่จุดสิ้นสุดของเชนของลิงก์สัญลักษณ์ไปยังไฟล์หรือชื่อที่ไม่ใช่ symlink สิ่งนี้อาจหรือไม่อาจให้ชื่อพา ธ สัมบูรณ์ขึ้นอยู่กับวิธีการทำ และหนึ่งอาจหรืออาจไม่ต้องการแก้ไขเป็นชื่อพา ธ สัมบูรณ์

คำสั่งที่readlink fooไม่มีตัวเลือกจะให้คำตอบก็ต่อเมื่ออาร์กิวเมนต์fooนั้นเป็นลิงก์สัญลักษณ์และคำตอบนั้นคือค่าของ symlink นั้น ไม่มีลิงก์อื่นติดตาม คำตอบอาจเป็นเส้นทางสัมพัทธ์: สิ่งที่เป็นค่าของอาร์กิวเมนต์ symlink

อย่างไรก็ตามreadlinkมีตัวเลือก (-f -e หรือ -m) ที่จะใช้งานได้กับไฟล์ทั้งหมดและให้ชื่อพา ธ สัมบูรณ์หนึ่งรายการ (ชื่อที่ไม่มี symlink) ให้กับไฟล์ซึ่งแสดงโดยอาร์กิวเมนต์

วิธีนี้ใช้ได้ผลดีกับทุกอย่างที่ไม่ใช่ symlink แต่อาจต้องการใช้ชื่อพา ธ สัมบูรณ์โดยไม่ต้องแก้ไข symlink ขั้นกลางบนพา ธ สิ่งนี้ทำโดยคำสั่งrealpath -s foo

ในกรณีของอาร์กิวเมนต์ symlink readlinkด้วยตัวเลือกจะแก้ไขsymlink ทั้งหมดบนพา ธ สัมบูรณ์ไปยังอาร์กิวเมนต์อีกครั้ง แต่จะรวมsymlink ทั้งหมดที่อาจพบโดยทำตามค่าอาร์กิวเมนต์ คุณอาจไม่ต้องการที่ถ้าคุณต้องการเส้นทางที่แน่นอนเพื่อโต้แย้ง symlink ตัวเองมากกว่าสิ่งที่มันอาจเชื่อมโยงไป อีกครั้งถ้าfooเป็น symlinkrealpath -s fooจะได้รับเส้นทางที่แน่นอนโดยไม่ต้องแก้ไขรวมถึงการกำหนดเป็นอาร์กิวเมนต์

หากไม่มี-sตัวเลือกrealpathก็จะทำเช่นเดียวกัน readlinkยกเว้นเพียงอ่านค่าของลิงก์และสิ่งอื่น ๆ อีกมากมาย มันไม่ชัดเจนสำหรับฉันว่าทำไมreadlinkมีตัวเลือกของมันสร้างความซ้ำซ้อนที่ไม่พึงประสงค์ด้วย realpathมีตัวเลือกของการสร้างเห็นได้ชัดซ้ำซ้อนที่ไม่พึงประสงค์ด้วย

การสำรวจเว็บไม่ได้บอกอะไรมากไปกว่านั้นยกเว้นว่าอาจมีการเปลี่ยนแปลงในบางระบบ

สรุป: realpathเป็นคำสั่งที่ดีที่สุดที่จะใช้อย่างยืดหยุ่นที่สุดอย่างน้อยสำหรับการใช้ที่ร้องขอที่นี่


10

ทางออกที่ฉันชอบคือหนึ่งโดย @EugenKonkov เพราะมันไม่ได้บ่งบอกถึงการมีอยู่ของสาธารณูปโภคอื่น ๆ (แพคเกจ coreutils)

แต่มันล้มเหลวสำหรับเส้นทางสัมพัทธ์ "." และ ".. " ดังนั้นนี่คือรุ่นที่ได้รับการปรับปรุงเล็กน้อยที่จัดการกับกรณีพิเศษเหล่านี้

มันยังคงล้มเหลวหากผู้ใช้ไม่มีสิทธิ์cdในการเข้าสู่ไดเรกทอรีหลักของเส้นทางสัมพัทธ์

#! /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
}

7

คำตอบของ Eugen ไม่ได้ผลสำหรับฉัน แต่สิ่งนี้ทำได้:

    absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"

หมายเหตุข้างไดเรกทอรีทำงานปัจจุบันของคุณไม่ได้รับผลกระทบ


ข้อสังเกต: นั่นคือสคริปต์ โดยที่ $ 1 เป็นอาร์กิวเมนต์แรกสำหรับมัน
Eugen Konkov

5

ที่ดีที่สุดของการแก้ปัญหา IMHO เป็นหนึ่งที่โพสต์ที่นี่: https://stackoverflow.com/a/3373298/9724628

มันต้องใช้ไพ ธ อนในการทำงาน แต่ดูเหมือนว่าจะครอบคลุมเคสทั้งหมดหรือส่วนใหญ่และเป็นโซลูชันแบบพกพา

  1. ด้วยการแก้ไข symlink:
python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
  1. หรือไม่มีมัน:
python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file

3

ในกรณีของfindอาจเป็นวิธีที่ง่ายที่สุดที่จะให้เส้นทางที่แน่นอนสำหรับการค้นหาเช่น:

find /etc
find `pwd`/subdir_of_current_dir/ -type f

3

หากคุณกำลังใช้ bash บน Mac OS X ซึ่งไม่มีrealpathอยู่และreadlinkไม่สามารถพิมพ์พา ธ สัมบูรณ์คุณอาจมีทางเลือก แต่ให้เขียนโค้ดเวอร์ชันของคุณเองเพื่อพิมพ์ นี่คือการดำเนินการของฉัน:

(ทุบตีบริสุทธิ์)

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[*]}"
)
}

(ใช้เพ่งพิศ)

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
}

(บริสุทธิ์ 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)
}

ตัวอย่าง:

$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war

1

สิ่งที่พวกเขาพูดยกเว้นfind $PWDหรือ (ในทุบตี) find ~+สะดวกกว่าเล็กน้อย


1

คล้ายกับคำตอบของ @ ernest-a แต่ไม่มีผลกระทบ$OLDPWDหรือกำหนดฟังก์ชั่นใหม่ที่คุณสามารถยิง subshell(cd <path>; pwd)

$ pwd
/etc/apache2
$ cd ../cups 
$ cd -
/etc/apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups

1

หากเส้นทางสัมพัทธ์เป็นเส้นทางไดเรกทอรีให้ลองของฉันควรเป็นเส้นทางที่ดีที่สุด:

absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)

echo $absPath

โซลูชันนี้ใช้งานได้กับทุบตีเท่านั้นดูstackoverflow.com/a/5193087/712014
Michael

1
echo "mydir/doc/ mydir/usoe ./mydir/usm" |  awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'

3
ขอบคุณสำหรับข้อมูลโค้ดนี้ซึ่งอาจให้ความช่วยเหลือระยะสั้นแบบ จำกัด คำอธิบายที่เหมาะสมจะช่วยเพิ่มมูลค่าในระยะยาวได้อย่างมากโดยการแสดงว่าทำไมนี่จึงเป็นวิธีแก้ปัญหาที่ดีและจะทำให้มีประโยชน์มากขึ้นสำหรับผู้อ่านในอนาคตด้วยคำถามอื่น ๆ ที่คล้ายกัน โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายรวมถึงข้อสมมติฐานที่คุณทำ
Toby Speight

1

การปรับปรุงเป็นเวอร์ชันที่ดีของ @ ernest-a:

absolute_path() {
    cd "$(dirname "$1")"
    case $(basename $1) in
        ..) echo "$(dirname $(pwd))";;
        .)  echo "$(pwd)";;
        *)  echo "$(pwd)/$(basename $1)";;
    esac
}

ข้อเสนอนี้อย่างถูกต้องกับกรณีที่องค์ประกอบสุดท้ายของเส้นทางคือ..ในกรณีที่"$(pwd)/$(basename "$1")"ในคำตอบ @ เออร์เนส-a accurate_sub_path/spurious_subdirectory/..จะผ่านมาเป็น


0

หากคุณต้องการแปลงตัวแปรที่มีเส้นทางสัมพัทธ์เป็นสัมพัทธ์สัมบูรณ์งานนี้:

   dir=`cd "$dir"`

"cd" echoes โดยไม่เปลี่ยนไดเรกทอรีการทำงานเพราะทำงานที่นี่ใน sub-shell


2
ใน bash-4.3-p46 มันใช้งานไม่ได้: เชลล์พิมพ์บรรทัดว่างเมื่อฉันรันdir=`cd ".."` && echo $dir
Michael

0

นี่เป็นโซลูชันที่ถูกโยงโซ่จากผู้อื่นทั้งหมดตัวอย่างเช่นเมื่อrealpathล้มเหลวเนื่องจากไม่ได้ถูกติดตั้งหรือออกจากด้วยรหัสข้อผิดพลาดดังนั้นจึงพยายามแก้ไขปัญหาถัดไปจนกว่าจะได้รับเส้นทางที่ถูกต้อง

#!/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")" "${?}"

0

คุณสามารถใช้การแทนที่สตริง bash สำหรับเส้นทาง $ line ใด ๆ ที่เกี่ยวข้อง:

line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line

การแทนที่ front-of-string พื้นฐานตามด้วยสูตร
$ {string / # substring / replace}
ซึ่งมีการกล่าวถึงที่นี่: https://www.tldp.org/LDP/abs/html/string-manipulation.html

\ตัวละครขัดแย้ง/เมื่อเราต้องการให้เป็นส่วนหนึ่งของสตริงที่เราพบ / แทนที่


0

ฉันไม่สามารถหาวิธีแก้ปัญหาที่พกพาได้อย่างเรียบร้อยระหว่าง Mac OS Catalina, Ubuntu 16 และ Centos 7 ดังนั้นฉันจึงตัดสินใจทำด้วย python inline และทำงานได้ดีสำหรับสคริปต์ทุบตีของฉัน

to_abs_path() {
  python -c "import os; print os.path.abspath('$1')"
}

to_abs_path "/some_path/../secrets"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.