การแปลงพา ธ สัมพัทธ์เป็นพา ธ สัมบูรณ์โดยไม่มีลิงก์สัญลักษณ์


คำตอบ:


79

คุณสามารถใช้readlinkยูทิลิตีพร้อม-fตัวเลือก:

-f, --canonicalize

      canonicalize  by  following  every symlink in every component of
      the given name recursively; all  but  the  last  component  must
      exist

การแจกแจงบางอย่างเช่นผู้ที่ใช้core GNUUและFreeBSDก็มาพร้อมกับrealpath(1)ยูทิลิตี้ที่โดยทั่วไปแล้วเพียงแค่เรียกrealpath(3)และทำสิ่งเดียวกัน


16
-fสวิทช์ไม่ได้อยู่บน Mac OS X (อย่างน้อย ณ 10.8.5) หากไม่มี-fสวิตช์ก็แค่ส่งคืนรหัสข้อผิดพลาด
iconoclast

3
ระบบบางมาพร้อมกับค่าreadlinkมิได้realpath- Solaris และ HP-UX โดยเฉพาะอย่างยิ่ง
Sildoreth

สำหรับปัญหา Mac: brew install coreutils apple.stackexchange.com/a/69332/23040และถ้าคุณไม่ต้องการที่จะทำขั้นตอนที่เปลี่ยนเส้นทางมาตรฐานเครื่องมือทั้งหมด Mac CLI ไปติดตั้งใหม่เทียบเท่า GNU greadlinkโทรเพียง
เอเดรีย

18

portably ที่PWDตัวแปรถูกกำหนดโดยเปลือกไปยังสถานที่หนึ่งที่แน่นอนของไดเรกทอรีปัจจุบัน องค์ประกอบใด ๆ ของเส้นทางนั้นอาจเป็นลิงก์สัญลักษณ์

case $f in
  /*) absolute=$f;;
  *) absolute=$PWD/$f;;
esac

หากคุณต้องการกำจัด.และ..เปลี่ยนไดเรกทอรีที่มีไฟล์และไปที่$PWDนั่น:

if [ -d "$f" ]; then f=$f/.; fi
absolute=$(cd "$(dirname -- "$f")"; printf %s. "$PWD")
absolute=${absolute%?}
absolute=$absolute/${f##*/}

ไม่มีวิธีพกพาในการติดตามลิงก์สัญลักษณ์ หากคุณมีเส้นทางไปยังไดเรกทอรีจากนั้นส่วนใหญ่$(cd -- "$dir" && pwd -P 2>/dev/null || pwd)แสดงให้เห็นเส้นทางที่ไม่ได้ใช้ลิงก์สัญลักษณ์เพราะเปลือกหอยที่ติดตามลิงก์สัญลักษณ์มีแนวโน้มที่จะใช้pwd -P("P" สำหรับ "ทางกายภาพ")

บาง Unices จัดให้มียูทิลิตี้ในการพิมพ์เส้นทาง "ทางกายภาพ" ไปยังไฟล์

  • ระบบลีนุกซ์รุ่นล่าสุดอย่างสมเหตุสมผล (พร้อม GNU coreutils หรือ BusyBox) มีreadlink -fเช่น FreeBSD .38.3, NetBSD ≥4.0, และ OpenBSD ไกลถึง 2.2
  • FreeBSD .34.3 มีrealpath(ยังมีอยู่ในระบบ Linux บางระบบและอยู่ใน BusyBox)
  • หาก Perl สามารถใช้ได้คุณสามารถใช้โมดูลCwd

    perl -MCwd -e 'print Cwd::realpath($ARGV[0])' path/to/file

ทำไมคุณถึงส่งบางสิ่งไปยังpwd( $(cd -- "$dir" && pwd -P 2>/dev/null | pwd)) ดูเหมือนจะไม่สนใจ stdin
Mateusz Piotrowski

1
@MateuszPiotrowski Typo ฉันตั้งใจจะเขียน||
Gilles

5

คือpwdเหมาะสำหรับความต้องการของคุณ มันให้เส้นทางที่แน่นอนของไดเรกทอรีปัจจุบัน หรืออาจจะเป็นสิ่งที่คุณต้องการคือrealpath ()


3

alisterและrss67ในบทความนี้แนะนำวิธีที่เสถียรที่สุดเข้ากันได้และง่ายที่สุด ฉันไม่เคยเห็นวิธีที่ดีกว่านี้มาก่อน

RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`

หากคุณต้องการกลับไปที่ตำแหน่งเดิม

ORGPATH=`pwd`
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd $ORGPATH

หรือ

RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd -

ฉันหวังว่านี่จะช่วยได้ นี่เป็นทางออกที่ดีที่สุดสำหรับฉัน


12
นั่นไม่ใช่วิธีที่ดีจริง ๆ การเปลี่ยนจากไดเรกทอรีและกลับเข้ามานั้นไม่น่าเชื่อถือ: คุณอาจไม่ได้รับอนุญาตให้กลับมาหรืออาจมีการเปลี่ยนชื่อไดเรกทอรีในระหว่างนี้ แต่เปลี่ยนไดเรกทอรีใน subshell ABSPATH=$(cd -- "$RELPATH" && pwd)นี้: หมายเหตุเครื่องหมายอัญประกาศคู่รอบการแทน (เพื่อไม่ให้แตกถ้าพา ธ ประกอบด้วยช่องว่างและอักขระกลม) และ--(ในกรณีที่พา ธ เริ่มต้นด้วย-) นอกจากนี้ยังใช้งานได้เฉพาะกับไดเรกทอรีและไม่เชื่อมโยงสัญลักษณ์สัญลักษณ์ตามที่ร้องขอ ดูคำตอบของฉันสำหรับรายละเอียดเพิ่มเติม
Gilles

"> คุณอาจไม่ได้รับอนุญาตให้กลับมา" คุณหมายถึง cd เป็น dir แต่ไม่สามารถย้อนกลับได้หรือไม่ คุณช่วยยกตัวอย่างสถานการณ์ให้คุณได้ไหม
Talespin_Kit

0

คำตอบอื่น ๆ ที่นี่ก็ดี แต่ก็ไม่เพียงพอสำหรับความต้องการของฉัน ฉันต้องการโซลูชันที่ฉันสามารถใช้ในสคริปต์ของฉันในเครื่องใดก็ได้ ทางออกของฉันคือการเขียนเชลล์สคริปต์ที่ฉันสามารถเรียกใช้จากสคริปต์ที่ฉันต้องการ

#!/bin/sh
if [ $# -eq 0 ] || [ $# -gt 2 ]; then
  printf 'Usage: respath path [working-directory]\n' >&2
  exit 1
fi
cantGoUp=

path=$1
if [ $# -gt 1 ]; then
  cd "$2"
fi
cwd=`pwd -P` #Use -P option to account for directories that are actually symlinks

#Handle non-relative paths, which don't need resolution
if echo "$path" | grep '^/' > /dev/null ; then
  printf '%s\n' "$path"
  exit 0
fi

#Resolve for each occurrence of ".." at the beginning of the given path.
#For performance, don't worry about ".." in the middle of the path.
while true
do
  case "$path" in
    ..*)
      if [ "$cwd" = '/' ]; then
        printf 'Invalid relative path\n' >&2
        exit 1
      fi
      if [ "$path" = '..' ]; then
        path=
      else
        path=`echo "$path" | sed 's;^\.\./;;'`
      fi
      cwd=`dirname $cwd`
      ;;
    *)
      break
      ;;
  esac
done

cwd=`echo "$cwd" | sed 's;/$;;'`
if [ -z "$path" ]; then
  if [ -z "$cwd" ]; then
    cwd='/'
  fi
  printf '%s\n' "$cwd"
else
  printf '%s/%s\n' "$cwd" "$path"
fi

โซลูชันนี้เขียนขึ้นสำหรับ Bourne Shell เพื่อความสะดวกในการพกพา ฉันมีสิ่งนี้ในสคริปต์ชื่อ "respath.sh"

สคริปต์นี้สามารถใช้ดังนี้:

respath.sh '/path/to/file'

หรือเช่นนี้

respath.sh '/relative/path/here' '/path/to/resolve/relative/to'

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


โปรดทราบว่าคุณอาจพบเชลล์เป้าหมายใน Solaris 10 และก่อนหน้านี้ทุกวัน ที่บอร์นเปลือกชอบมากที่สุดบอร์นการใช้งานตั้งแต่เปลือก SVR2 (1984) ได้pwdbuiltin และไม่สนับสนุนการ-P(บอร์นเชลล์ไม่ได้ดำเนินการตามที่ $ PWD ตรรกะจัดการเช่นเปลือกหอย POSIX ทำ)
Stéphane Chazelas

หากคุณทิ้งความเข้ากันได้ของ Bourne คุณสามารถใช้ไวยากรณ์ POSIX $ {var ## pattern} และหลีกเลี่ยง echo | sed ที่กำลังจะทำลายด้วยค่าบางค่า
Stéphane Chazelas

คุณลืมตรวจสอบสถานะการออกของ cd (และ pwd) คุณอาจจะใช้cd -P --เช่นเดียวกับในกรณีที่อาร์กิวเมนต์ที่ 1 มีบางส่วน ..
Stéphane Chazelas

คุณcaseตรวจสอบควรจะแทน..|../*) ..*
Stéphane Chazelas

มีหนึ่งกรณีของคำพูดที่ขาดหายไปในdirname $cwd
Stéphane Chazelas

0

ในกรณีนอกจากนี้คุณมีเส้นทางที่กำหนดไว้ล่วงหน้าสำหรับ$1(โดยปกติ${PWD}) บางอย่างต่อไปนี้จะทำงาน:

CWD="${1:-${PredefinedAbsolutePath}}"
if [ "${CWD}" != "${PredefinedAbsolutePath}}" ]; then
    case $1 in
        /*) echo "CWD=${CWD}"; ;;
        *) CWD=$(realpath $1); echo "CWD=${CWD}"; ;;
    esac
fi

0

ฉันพบว่าฟังก์ชั่นด้านล่างนั้นง่ายและพกพาได้ระหว่าง linux / MAC OSX เมื่อเทียบกับคนอื่น ๆ ที่ฉันพบทุกที่ อาจช่วยใครซักคน

#!/usr/bin/bash
get_absolute_path(){
    file_path=`pwd $1`
    echo "$file_path/$1"
}
#to assign to a variable
absolute_path=$(get_absolute_path "file.txt")
echo $absolute_path

-1

สมมติว่าตัวแปรจัดเก็บชื่อพา ธ (a = "อะไรก็ตาม")

1.สำหรับเส้นทางที่มีพื้นที่ว่าง:

c=$(grep -o " " <<< $a | wc -l); if (( $c > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi

2.สำหรับคำถามจริงเช่นการแปลงพา ธ เป็นสัมบูรณ์: readlinkสามารถดึงเนื้อหา symlink ซึ่งสามารถใช้งานได้ดังต่อไปนี้ (หมายเหตุreadlink -fจะสมบูรณ์ แต่ไม่มีใน Mac OS X อย่างน้อย bash ซึ่ง-fหมายถึงFORMATS )

if [[ $(readlink $a) == "" ]]; then a=$(cd $a; pwd); else a=$(cd $(readlink $a); pwd); fi

3.เพิ่งเรียนรู้pwd -Pในman pwd: -P คือ " แสดงไดเรกทอรีทำงานปัจจุบันทางกายภาพ (ลิงก์สัญลักษณ์ทั้งหมดได้รับการแก้ไข) " และด้วยเหตุนี้

if (( $(grep -o " " <<< $a | wc -l) > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi; a=$(cd $a; pwd -P)

จะทำงานด้วย

สรุป:รวม1กับ2เพื่อตอบสนองทั้งความต้องการของคุณในขณะที่พื้นที่ที่มีชื่อเส้นทางเป็นที่เรียบร้อยแล้วการดูแลในรัดกุมมากขึ้น3


คุณ gu ผิด (ess) ผิด เช่นถ้าเส้นทางของคุณมีพื้นที่ส่วนใหญ่ข้างต้นจะไม่ทำงาน
Anthon

หรือถ่านกลมบางครั้ง และมันก็ไม่สามารถแก้ไข symlink ได้ตามที่ร้องขอ
dave_thompson_085

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