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


448

คำถาม: มีคำสั่ง sh / bash / zsh / fish / ... อย่างง่าย ๆ เพื่อพิมพ์พา ธ สัมบูรณ์ของไฟล์ใดก็ตามที่ฉันป้อน

กรณีการใช้งาน: ฉันในไดเรกทอรี/a/bและฉันต้องการพิมพ์เส้นทางแบบเต็มไปยังไฟล์บนบรรทัดคำสั่งเพื่อที่ฉันสามารถวางลงในโปรแกรมอื่น:c /a/b/cเรียบง่าย แต่โปรแกรมเล็ก ๆ น้อย ๆ ในการทำเช่นนี้อาจช่วยฉันได้ 5 หรือประมาณวินาทีในการจัดการเส้นทางที่ยาวซึ่งในที่สุดจะเพิ่มขึ้น ดังนั้นฉันจึงประหลาดใจที่ฉันไม่สามารถหายูทิลิตี้มาตรฐานเพื่อทำสิ่งนี้ - ไม่มีจริงเหรอ?

นี่คือตัวอย่างการใช้งาน abspath.py:

#!/usr/bin/python
# Author: Diggory Hardy <diggory.hardy@gmail.com>
# Licence: public domain
# Purpose: print the absolute path of all input paths

import sys
import os.path
if len(sys.argv)>1:
    for i in range(1,len(sys.argv)):
        print os.path.abspath( sys.argv[i] )
    sys.exit(0)
else:
    print >> sys.stderr, "Usage: ",sys.argv[0]," PATH."
    sys.exit(1)

ฉันขอยืนยันว่า @ DennisWilliamson คำตอบ (โดยใช้ตัวเลือก -m) นั้นยอดเยี่ยมสำหรับ (โดยปกติ) เป็นแบบพกพาและทำงานกับไฟล์ที่ไม่มีอยู่จริง
TTT

หรือคำตอบของ Flimm ทั้งสองเป็นทางออกที่ดี อย่างไรก็ตาม Bannier ตอบคำถามดั้งเดิมของฉันได้ดีที่สุด
dhardy

3
ผู้ใช้ OSX: ดูคำตอบนี้
เอียน

คำตอบ:


562

ลองrealpathดู

$ realpath example.txt
/home/username/example.txt

133
+1 โปรแกรมที่ดีมาก แต่โปรดทราบว่ามันเป็นคำสั่งภายนอก (ไม่ใช่เชลล์ในตัว) และอาจไม่มีอยู่ในทุกระบบโดยค่าเริ่มต้นนั่นคือคุณอาจต้องติดตั้ง ใน Debian มันจะอยู่ในแพ็คเกจแยกต่างหากที่มีชื่อเดียวกัน
Roman Cheplyaka

5
ฉันเพิ่มเส้นทางของฉันrealpathประกอบด้วย: github.com/westonruter/misc-cli-tools/blob/master/realpath
Weston Ruter

1
@Flimm: มันจะยังคงให้เส้นทางที่ถูกต้องกับคุณในบางเส้นทาง หากคุณต้องการทราบเกี่ยวกับการมีอยู่ของไฟล์ให้ใช้เครื่องมืออื่นเช่นการทดสอบ
Benjamin Bannier

14
@Dalin: ลองติดตั้ง coreutils ไบนารีมีชื่อว่า grealpath
Toni Penya-Alba

5
เครื่องมือนี้ถูกนำมาใช้ใน GNU coreutils 8.15 (ในปี 2012) ดังนั้นมันค่อนข้างใหม่
marbu

319

ลองใช้readlinkซึ่งจะแก้ไขลิงก์สัญลักษณ์:

readlink -e /foo/bar/baz

50
ฉันอยากจะใช้ '-f' แทน '-e' เพื่อให้เราเห็นเส้นทางที่แน่นอนของไฟล์ที่ไม่มีอยู่
hluk

5
ดูเหมือนว่าจะง่ายที่สุดสำหรับฉันในขณะที่พกพาได้ readlink เป็นพอร์ตของ gnu coreutils ดังนั้นมันจะถูกติดตั้งในการแจกจ่าย linux เกือบทุกชนิดยกเว้นบางตัวที่ฝังอยู่
catphive

14
สำหรับฉันแล้ว-mมันเป็นตัวเลือกที่ดีที่สุดที่จะใช้
Matt Joiner

1
@Dalin: /usr/bin/readlinkบน Mavericks หรือคุณหมายถึงไม่พบตัวเลือกเหล่านั้นใน OS X ดูเหมือนว่าจะเป็นรุ่น BSD ที่แสดงความสามารถ ... : p
iconoclast

14
@iconoclast ตัวเลือกเหล่านั้นไม่สามารถใช้ได้ใน OSX และตามreadlinkmanpage BSD : only the target of the symbolic link is printed. If the given argument is not a symbolic link, readlink will print nothing and exit with an errorดังนั้น readlink จะไม่ทำงานเพื่อจุดประสงค์นี้ใน OSX
SnoringFrog

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

8
อย่าลืมพูดทุกสิ่ง หากคุณไม่เข้าใจว่าทำไมลองใช้โปรแกรมของคุณกับไฟล์a b(ช่องว่างสองช่องระหว่าง a และ b ดังนั้นกินหนึ่งในนั้น)
Roman Cheplyaka

1
ลองใช้วิธีนี้กับ "/" เปลี่ยนเป็น "///"
จอร์จ

35
โซลูชัน POSIX เพียงตัวเดียวที่ไม่ต้องการให้คุณเขียนและรวบรวมไฟล์ที่เรียกทำงานได้เนื่องจาก readlink และ realpath ไม่ใช่ POSIX
Ciro Santilli 郝海东冠状冠状病六四事件法轮功

25
ฉันเคยfunction realpath { echo $(cd $(dirname $1); pwd)/$(basename $1); }ทำให้ตัวเองเป็นrealpathคำสั่ง (คำตอบที่ยอมรับในปัจจุบัน) ใน OS X ขอบคุณ!
James Bedford

1
ฉันใช้วิธีนี้เพื่อกำหนดชื่อไฟล์บันทึกสำหรับสคริปต์:LOG=$(echo $(cd $(dirname $0); pwd)/$(basename $0 .sh).log)
DrStrangepork

85

ลืมreadlinkและrealpathอาจจะติดตั้งในระบบของคุณหรือไม่

การขยายคำตอบของ dogbaneด้านบนจะแสดงเป็นฟังก์ชัน:

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
}

จากนั้นคุณสามารถใช้สิ่งนี้:

myabsfile=$(get_abs_filename "../../foo/bar/file.txt")

มันทำงานอย่างไรและทำไม?

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

ทำไมฉันถึงชอบวิธีนี้?

มันเป็นแบบพกพาและไม่จำเป็นต้องมีreadlinkหรือrealpathที่มักจะไม่อยู่ในการติดตั้งเริ่มต้นของ distro Linux / Unix ที่กำหนด

เกิดอะไรขึ้นถ้าไม่มี dir?

ตามที่ระบุไว้ข้างต้นฟังก์ชั่นจะล้มเหลวและพิมพ์บน stderr หากเส้นทางไดเรกทอรีที่กำหนดไม่มีอยู่ นี่อาจไม่ใช่สิ่งที่คุณต้องการ คุณสามารถขยายฟังก์ชั่นเพื่อจัดการกับสถานการณ์นั้น:

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  if [ -d "$(dirname "$1")" ]; then
    echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
  fi
}

ตอนนี้มันจะส่งคืนสตริงว่างเปล่าถ้าไม่มี dirs พาเรนต์อยู่

คุณจัดการกับ '.. ' หรือ 'ต่อท้ายได้อย่างไร ในการป้อนข้อมูล?

มันให้เส้นทางที่แน่นอนในกรณีนั้น แต่ไม่ใช่เส้นทางที่น้อยที่สุด มันจะมีลักษณะ:

/Users/bob/Documents/..

หากคุณต้องการแก้ไข '.. ' คุณจะต้องสร้างสคริปต์เช่น:

get_abs_filename() {
  # $1 : relative filename
  filename=$1
  parentdir=$(dirname "${filename}")

  if [ -d "${filename}" ]; then
      echo "$(cd "${filename}" && pwd)"
  elif [ -d "${parentdir}" ]; then
    echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")"
  fi
}

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

3
ฉันต้องการที่จะเพิ่มที่realpathมาจากแพคเกจ coreutils ซึ่งนอกจากนี้ยังมีเครื่องมือเช่นwho, หรือtouch catเป็นชุดเครื่องมือ GNU ที่ค่อนข้างโดดเด่นดังนั้นคุณสามารถมั่นใจได้ว่านี่ติดตั้งในเครื่องที่ใช้ linux เกือบทุกเครื่องกล่าวได้ว่าคุณพูดถูก: มี 2 ประเด็น: i) คุณอาจพลาดการติดตั้งเริ่มต้นบน ไม่ใช่ระบบ GNU unix (เช่น OpenBSD) ii) เครื่องมือนี้เปิดตัวในเวอร์ชัน 8.15 (ดังนั้นจึงค่อนข้างใหม่ตั้งแต่ปี 2012) ดังนั้นคุณจะพลาดมันในระบบเสถียรระยะยาว (เช่น RHEL 6)
marbu

1
อย่างน้อยก็ดูเหมือนว่าอย่างต่อเนื่อง Analytics (ผู้ผลิตของการแจกจ่ายงูใหญ่งูเหลือม ) ชอบคำตอบนี้ มันถูกนำไปใช้ (โดยมีการอ้างอิงลิงก์กลับมาที่นี่) ในสคริปต์ "เปิดใช้งาน"ซึ่งใช้เพื่อเปิดใช้งานสภาพแวดล้อมเสมือนที่สร้างขึ้นโดยเครื่องมือ conda ดังนั้น…หนึ่งที่ดี!
wjv

1
ใช้งานได้เฉพาะกับไดเรกทอรี (เนื่องจากไม่มีอื่น ๆ ) และไม่สามารถรับมือกับ ".. " และ "ได้" ดูคำตอบของฉันที่ควรจัดการทุกอย่าง: stackoverflow.com/a/23002317/2709
Alexander Klimetschek

3
@marbu realpath ไม่มีอยู่ใน Ubuntu 14.04 หรือบน Debian Wheezy มันอาจจะค่อนข้างมาตรฐานเมื่อเวลาผ่านไป แต่ตอนนี้ไม่แน่นอน โปรดทราบด้วยว่า OP ไม่ได้พูดอะไรเกี่ยวกับ linux หรือ GNU Bash มีการใช้กันอย่างแพร่หลายมากกว่านั้น
mc0e

77
$ readlink -m FILE
/path/to/FILE

สิ่งนี้ดีกว่าreadlink -e FILEหรือrealpathเพราะใช้งานได้แม้ว่าไฟล์จะไม่มีอยู่


ดี สิ่งนี้ใช้ได้กับไฟล์ / ไดเรกทอรีที่มีอยู่ แต่ไม่ใช่ symlink
quietmint

ฉันมี readlink อยู่ใน OS X 10.9 (Mavericks) ดังนั้นนี่คือคำตอบที่ดีที่สุด
Kenneth Hoste

6
@KennethHoste: ไม่มี-mตัวเลือกใน Mavericks
iconoclast

2
ไม่ได้อยู่ในการติดตั้ง DEFAULT OSX แน่นอน
Fran Marzoa

ทำงานบน linux (CentOS) ขอบคุณเนื่องจาก realpath ไม่มีอยู่จริง
jimh

66

เส้นทางสัมพัทธ์นี้ไปยังฟังก์ชันเชลล์ตัวแปลงเส้นทางแบบสัมบูรณ์

  • ไม่ต้องใช้สาธารณูปโภค (เพียงcdและpwd)
  • ทำงานกับไดเรกทอรีและไฟล์
  • จับ..และ.
  • จัดการช่องว่างใน dir หรือชื่อไฟล์
  • ต้องมีไฟล์หรือไดเรกทอรีนั้น
  • ไม่ส่งคืนสิ่งใดหากไม่มีสิ่งใดในเส้นทางที่กำหนด
  • จัดการเส้นทางที่แน่นอนเป็นอินพุต (ส่งผ่านพวกเขาเป็นหลัก)

รหัส:

function abspath() {
    # generate absolute path from relative path
    # $1     : relative filename
    # return : absolute path
    if [ -d "$1" ]; then
        # dir
        (cd "$1"; pwd)
    elif [ -f "$1" ]; then
        # file
        if [[ $1 = /* ]]; then
            echo "$1"
        elif [[ $1 == */* ]]; then
            echo "$(cd "${1%/*}"; pwd)/${1##*/}"
        else
            echo "$(pwd)/$1"
        fi
    fi
}

ตัวอย่าง:

# assume inside /parent/cur
abspath file.txt        => /parent/cur/file.txt
abspath .               => /parent/cur
abspath ..              => /parent
abspath ../dir/file.txt => /parent/dir/file.txt
abspath ../dir/../dir   => /parent/dir          # anything cd can handle
abspath doesnotexist    =>                      # empty result if file/dir does not exist
abspath /file.txt       => /file.txt            # handle absolute path input

หมายเหตุ: สิ่งนี้ขึ้นอยู่กับคำตอบจาก nolan6000และbsinghแต่จะแก้ไขตัวพิมพ์

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


ขอบคุณ นั่นคือสิ่งที่ฉันไปด้วยใน OSX
Greg

นี้ไม่ได้ทำงานให้กับไดเรกทอรีที่มีช่องว่างเช่น: $ abspath 'a b c/file.txt'นั่นเป็นเพราะการโต้แย้งที่จะcdไม่ได้ยกมา เพื่อเอาชนะสิ่งนี้แทนที่จะอ้างถึงข้อโต้แย้งทั้งหมดเพื่อecho(มีเหตุผลสำหรับคำพูดเหล่านี้หรือไม่) อ้างถึงเพียงอาร์กิวเมนต์เส้นทาง คือแทนที่ด้วยecho "$(cd ${1%/*}; pwd)/${1##*/}" echo $(cd "${1%/*}"; pwd)/${1##*/}
george

@ จอร์จขอบคุณที่สังเกตฉันฉันคง
Alexander Klimetschek

1
ฉันลองดูวิธีแก้ปัญหาแบบครึ่งโหลและสิ่งนี้ดูเหมือนจะเป็นวิธีแก้ปัญหาที่กระชับและแม่นยำที่สุด คุณสามารถบางมากยิ่งขึ้นโดยการแทนที่ด้วยecho "$(cd "$1"; pwd)" (cd "$1"; pwd)ไม่จำเป็นต้องมีเสียงก้องที่นี่
หก

@Six True ได้รับการอัปเดต วงเล็บ( ... )ที่มีความจำเป็นยังคงเพื่อให้cdเกิดขึ้นใน subshell abspathในขณะที่เราไม่ต้องการที่จะเปลี่ยนไดเรกทอรีการทำงานสำหรับการโทรติดต่อใด
Alexander Klimetschek

24

findคำสั่งอาจช่วย

find $PWD -name ex*
find $PWD -name example.log

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

find $PWD

ฉันใช้สิ่งนี้กับ Solaris 10 ซึ่งไม่มีสาธารณูปโภคอื่น ๆ ที่กล่าวถึง


1
ฉันไม่ได้อ่านความคิดเห็นนี้ในการอ่านครั้งแรก; จุดสำคัญที่นี่คือถ้าคุณให้เส้นทางที่แน่นอนไปที่คำสั่ง find แล้วมันจะส่งผลให้ผลลัพธ์ในเส้นทางที่แน่นอน ดังนั้นการใช้ $ PWD เป็นเส้นทางสัมบูรณ์ของตำแหน่งที่คุณอยู่ดังนั้นคุณจะได้ผลลัพธ์ที่แน่นอน
simbo1905

4
หากคุณอาศัยคุณก็สามารถใช้PWD $PWD/$filename
jonny

วิธีการนี้สามารถปรับปรุงได้ด้วยการใช้ -maxdepth 1 และอย่าลืมเกี่ยวกับการอ้างถึง - ปัญหาด้านความปลอดภัยที่อาจเกิดขึ้นที่นี่ขึ้นอยู่กับวิธีที่คุณใช้สิ่งนี้
mc0e

1
@ จอนนี่: $ PWD / $ ชื่อไฟล์ล้มเหลวหากชื่อไฟล์ $ เป็นแบบสัมบูรณ์แล้ว
mc0e

สิ่งนี้จะล้มเหลวหากได้รับชื่อไฟล์เป็น "./filename.txt" (พร้อมจุดนำและเครื่องหมายทับ)
Mark Stosberg

15

หากคุณไม่มียูทิลิตี้ readlink หรือ realpath กว่าที่คุณสามารถใช้ฟังก์ชั่นต่อไปนี้ซึ่งทำงานใน bash และ zsh (ไม่แน่ใจเกี่ยวกับส่วนที่เหลือ)

abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }

วิธีนี้ใช้ได้กับไฟล์ที่ไม่มีอยู่ (เช่นเดียวกับฟังก์ชัน python os.path.abspath )

น่าเสียดายที่abspath ./../somefileไม่ได้กำจัดจุดต่าง ๆ


1
ดูเป็นแบบพกพาสำหรับฉัน ในทางกลับกันจะแบ่งตัวอย่างเช่นในชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่
Roman Cheplyaka

1
เพื่อปรับปรุงเพิ่มเติมแทนที่ echo "$1"ด้วยprintf "%s\n" "$1"(เหมือนกับเสียงสะท้อนที่สอง) echoอาจตีความแบ็กสแลชภายในอาร์กิวเมนต์
Roman Cheplyaka

อีกครั้งคุณพูดถูก! จริงๆแล้วพฤติกรรมของคำสั่ง echo ใน zsh นั้นแตกต่างจาก bash
hluk

1
พูดอย่างเคร่งครัดภายใต้พฤติกรรม POSIX ของ echo จะไม่ได้กำหนดถ้าอาร์กิวเมนต์มีแบ็กสแลช อย่างไรก็ตามมีการกำหนดไว้ภายใต้ส่วนขยาย XSI (กล่าวคือ echo ควรตีความลำดับการหลีกเลี่ยง) แต่ทั้ง bash และ zsh นั้นยังห่างไกลจาก POSIX ...
Roman Cheplyaka

ขออภัยฉันไม่เห็นประเด็น ฉันได้ให้คำตอบในฐานะสคริปต์ที่มีคุณสมบัติเพิ่มเติมซึ่งไม่จำเป็นต้องใช้ภายในสคริปต์เชลล์
dhardy

10

นี่คือฟังก์ชั่น zsh-only ที่ฉันชอบสำหรับความกะทัดรัด ใช้ตัวขยายการขยาย 'A' - ดู zshexpn (1)

realpath() { for f in "$@"; do echo ${f}(:A); done }

ว้าวนั่นเป็นทางออกที่สง่างาม !!
ShellFish

6

โดยทั่วไปมีสิ่งดังกล่าวไม่เป็นไปยังแฟ้ม (คำสั่งนี้หมายถึงว่าอาจจะมีมากกว่าหนึ่งโดยทั่วไปจึงใช้บทความที่แน่นอนไม่เหมาะสม) An คือเส้นทางใด ๆ ที่เริ่มต้นจากรูท "/" และกำหนดไฟล์โดยไม่มีความกำกวมโดยอิสระจากไดเร็กทอรีการทำงาน (ดูตัวอย่างวิกิพีเดีย ) absolute pathabsolute path

A relative pathเป็นเส้นทางที่จะตีความเริ่มต้นจากไดเรกทอรีอื่น มันอาจเป็นไดเร็กตอรี่ที่ใช้งานได้ถ้ามันrelative pathถูกจัดการโดยแอปพลิเคชั่น (แต่ไม่จำเป็น) เมื่ออยู่ในลิงก์สัญลักษณ์ในไดเรกทอรีโดยทั่วไปมีวัตถุประสงค์เพื่อสัมพันธ์กับไดเรกทอรีนั้น (แม้ว่าผู้ใช้อาจมีการใช้อื่น ๆ ในใจ)

ดังนั้นพา ธ สัมบูรณ์เป็นเพียงพา ธ ที่สัมพันธ์กับรูทไดเร็กทอรี

เส้นทาง (สัมบูรณ์หรือสัมพัทธ์) อาจมีหรือไม่มีลิงก์สัญลักษณ์ หากไม่เป็นเช่นนั้นก็ค่อนข้างจะไม่สามารถเปลี่ยนแปลงโครงสร้างการเชื่อมโยงได้ แต่ก็ไม่จำเป็นต้องใช้หรือต้องการแม้กระทั่ง บางคนเรียกcanonical path(หรือcanonical file nameหรือresolved path) absolute pathซึ่งลิงก์สัญลักษณ์ทั้งหมดได้รับการแก้ไขนั่นคือถูกแทนที่ด้วยเส้นทางไปยังที่ใดก็ตามที่พวกเขาเชื่อมโยงไป คำสั่งrealpathและreadlinkทั้งสองมองหาเส้นทางที่ยอมรับ แต่เพียงอย่างเดียวrealpathมีตัวเลือกสำหรับการรับเส้นทางแบบสัมบูรณ์โดยไม่ต้องรบกวนการแก้ไขลิงก์สัญลักษณ์ (พร้อมกับตัวเลือกอื่น ๆ เพื่อรับเส้นทางประเภทต่างๆแบบสัมบูรณ์หรือสัมพันธ์กับไดเรกทอรีบางส่วน)

สิ่งนี้เรียกร้องความคิดเห็นหลายประการ:

  1. ลิงก์สัญลักษณ์สามารถแก้ไขได้หากสิ่งที่ควรจะเชื่อมโยงไปยังถูกสร้างขึ้นแล้วซึ่งเห็นได้ชัดว่าไม่ใช่ทุกกรณี คำสั่งrealpathและreadlinkมีตัวเลือกในการบัญชีสำหรับที่
  2. canonicalไดเรกทอรีบนเส้นทางที่ต่อมาจะกลายเป็นสัญลักษณ์การเชื่อมโยงซึ่งหมายความว่าเส้นทางจะไม่มีอีกต่อไป ดังนั้นแนวคิดจึงขึ้นอยู่กับเวลา (หรือสภาพแวดล้อม)
  3. แม้ในกรณีที่เหมาะสมที่สุดเมื่อลิงก์สัญลักษณ์ทั้งหมดสามารถแก้ไขได้อาจยังมีมากกว่าหนึ่งลิงก์ canonical pathมีไฟล์ไฟล์ด้วยสองสาเหตุ:
    • พาร์ติชันที่มีไฟล์อาจถูกเมาท์พร้อมกัน (ro ) ในหลายจุดเมานท์
    • อาจมีการเชื่อมโยงไปยังไฟล์อย่างหนักซึ่งหมายความว่าไฟล์นั้นมีอยู่ในหลาย ๆ ไดเรกทอรี

ดังนั้นแม้จะมีคำจำกัดความที่เข้มงวดมากขึ้นcanonical pathแต่ก็อาจมีหลายเส้นทางที่เป็นที่ยอมรับไปยังไฟล์ นี่ก็หมายความว่าผู้คัดเลือกมีคุณสมบัติcanonicalไม่เพียงพอเนื่องจากมักแสดงถึงแนวคิดเรื่องความเป็นเอกลักษณ์

สิ่งนี้จะขยายการอภิปรายสั้น ๆ ของหัวข้อในคำตอบของคำถามที่คล้ายกันอื่นที่Bash: ดึงเส้นทางสัมบูรณ์ที่ได้รับจากญาติ

ข้อสรุปของฉันคือว่าคือการออกแบบที่ดีขึ้นและมีความยืดหยุ่นมากขึ้นกว่าrealpath readlinkการใช้งานเพียงอย่างเดียวreadlinkที่ไม่ได้ครอบคลุมrealpathคือการโทรโดยไม่มีตัวเลือกคืนค่าของลิงก์สัญลักษณ์


ฉันไม่รังเกียจที่จะถูก downvote แต่ฉันชอบที่จะเข้าใจว่าทำไมเพื่อให้ฉันสามารถเรียนรู้บางสิ่งบางอย่างไม่ว่าจะเป็นทางเทคนิคหรือเกี่ยวกับสิ่งที่ถือว่าเป็นวิธีปฏิบัติที่เหมาะสมในเว็บไซต์ อืม ... อย่างน้อยก็ชักชวนให้ฉันลงทะเบียนกับMeta Stack Overflowเพื่อทำความเข้าใจกับสังคมวิทยาท้องถิ่น ฉันแนะนำมัน - ยังถ้าใครมีความคิดเห็นเกี่ยวกับความไม่เหมาะสมของคำตอบของฉันฉันสนใจ
babou

1
(a) คำถามนี้มีคำตอบที่ถูกต้องจาก 2 + 1/2 ปีที่ผ่านมา (b) มีเส้นทางสัมบูรณ์ (เดียว) ที่สอดคล้องกับเส้นทางสัมพัทธ์ (ซึ่งเป็นสิ่งที่ฉันต้องการ) แม้ว่าอาจจะไม่ใช่ไฟล์เหมือนคุณ ชี้ให้เห็น. BTW ความคิดเห็นใด ๆ เกี่ยวกับrealpathvs readlinkหรือแม้แต่เกี่ยวกับลิงก์สัญลักษณ์นั้นเป็นสิ่งที่ฉันถาม
dhardy

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

5
1- ความจริงที่ว่าคำถามมีคำตอบที่ถูกต้องเป็นเวลานานไม่ได้หมายความว่าจะถูกปิด คำถามไม่ได้มีไว้สำหรับการใช้งานส่วนตัวเท่านั้น แน่นอนว่ามีป้ายสำหรับคำตอบที่รวบรวมคะแนนมากกว่าคำตอบที่ตรวจสอบแล้ว และด้วยเครื่องมือใหม่คำตอบ "ดีที่สุด" สามารถเปลี่ยนแปลงได้ตลอดเวลา หลายคนใช้คำตอบเก่า ๆ ที่เข้าถึงผ่านการค้นหาเว็บ
babou

1
2 - คุณยืนยันว่ามี (เดี่ยว) เส้นทางที่แน่นอนสอดคล้องกับทางญาติ ในขณะที่ฉันเดาว่าคุณหมายถึงอะไรโดย "สอดคล้องกัน" คือเส้นทางที่ได้มาจากต้นฉบับผ่านชุดการแปลงที่กำหนดคำสั่งของคุณยังคงไม่ถูกต้อง มีเส้นทางที่เป็นเอกลักษณ์ "สอดคล้อง" เป็นเอกลักษณ์ คำนี้canonicalหมายถึงเอกลักษณ์เฉพาะที่สัมพันธ์กับชุดการเปลี่ยนแปลง แต่ตัวอย่างเช่น / dev / cdrom เป็นเส้นทางสัมบูรณ์ที่สมบูรณ์แบบแม้ว่ามันจะเป็นลิงค์ไปยัง / dev / sr0 ทั้งสองชี้ไปที่อุปกรณ์เดียวกัน คำตอบเดิมของฉันชี้ไปที่บทความบนเว็บที่เกี่ยวข้อง
babou

5

dogbane คำตอบที่มีคำอธิบายสิ่งที่กำลังจะมาเมื่อ:

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

คำอธิบาย:

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

2

สำหรับไดเรกทอรีที่dirnameได้รับการสะดุดสำหรับการและผลตอบแทน.././

ฟังก์ชั่นของ nolan6000สามารถแก้ไขได้เพื่อแก้ไข:

get_abs_filename() {
  # $1 : relative filename
  if [ -d "${1%/*}" ]; then
    echo "$(cd ${1%/*}; pwd)/${1##*/}"
  fi
}

1
ยินดีต้อนรับสู่ SO! สำหรับการเปลี่ยนแปลงและข้อสังเกตเล็กน้อยการเพิ่มความคิดเห็นในคำตอบที่มีอยู่อาจเหมาะสมกว่าการเพิ่มคำตอบโดยเฉพาะอย่างยิ่งหากคำตอบที่คัดลอกนี้ขาดข้อมูลอื่น ๆ ของคำตอบดั้งเดิมจำนวนมาก เมื่อคุณได้รับชื่อเสียงเพิ่มขึ้นอีกเล็กน้อยคุณสามารถเพิ่มความคิดเห็นในคำตอบของผู้อื่นได้ สำหรับตอนนี้พยายามรวบรวมชื่อเสียงด้วยการถามคำถามที่มีค่าและมีเอกลักษณ์หรือให้คำตอบที่ดี
cfi

1
เนื่องจากคุณอ้างถึงคำตอบของ nolan6000 โปรดทราบว่าผู้ลงโฆษณาแสดงความคิดเห็นแล้วว่าเขาจะไม่ยอมรับคำตอบของ nolan6000 เพราะเขาไม่ได้มองหาสคริปต์ ดังนั้นการพูดคำตอบของคุณอย่างเคร่งครัดไม่ตอบคำถาม
cfi

สามารถเพิ่มฟังก์ชัน.profileและพร้อมใช้งานสำหรับการโต้ตอบ
adib

สิ่งนี้จะไม่ทำงานหาก$1เป็นชื่อไฟล์ธรรมดา: get_abs_filename foo-> ไม่มีอะไร (หรือ<current_dir>/foo/fooถ้าfooเป็นไดเรกทอรี)
ivan_pozdeev

2

นี่ไม่ใช่คำตอบสำหรับคำถาม แต่สำหรับผู้ที่ทำสคริปต์:

echo `cd "$1" 2>/dev/null&&pwd||(cd "$(dirname "$1")";pwd|sed "s|/*\$|/${1##*/}|")`

มันจัดการ / .. ./ ฯลฯ อย่างถูกต้อง ฉันก็ดูเหมือนว่าจะทำงานบน OSX


2

ฉันได้วางสคริปต์ต่อไปนี้บนระบบของฉัน & ฉันเรียกว่าเป็น bash alias แทนเมื่อฉันต้องการคว้าพา ธ แบบเต็มไปยังไฟล์ใน dir ปัจจุบัน:

#!/bin/bash
/usr/bin/find "$PWD" -maxdepth 1 -mindepth 1 -name "$1"

ฉันไม่แน่ใจว่าทำไม แต่ใน OS X เมื่อเรียกใช้โดยสคริปต์ "$ PWD" จะขยายไปสู่เส้นทางที่แน่นอน เมื่อคำสั่ง find ถูกเรียกบนบรรทัดคำสั่งมันจะไม่ทำงาน แต่มันทำในสิ่งที่ฉันต้องการ ... เพลิดเพลิน


$PWDมีพา ธ สัมบูรณ์ของไดเร็กทอรีการทำงานเสมอ นอกจากนี้findจะไม่ยอมรับเครื่องหมายทับดังนั้นคุณไม่ต้องตอบคำถามตามที่ถาม วิธีที่รวดเร็วในการทำสิ่งที่คุณกำลังมองหาที่จะทำก็จะecho "$PWD/$1"
อดัมแคทซ์

2

ง่ายที่สุดถ้าคุณต้องการใช้บิวด์อินเท่านั้น:

find `pwd` -name fileName

เพิ่มคำสองคำเท่านั้นและจะใช้ได้กับระบบยูนิกซ์ทั้งหมดเช่นเดียวกับ OSX


ฉันจะเพิ่ม-maxdepth 1ก่อน-name(สมมติว่าไฟล์อยู่ในไดเรกทอรีปัจจุบัน) หากไม่มีมันจะทำงานกับไฟล์ในไดเรกทอรีย่อยใด ๆ ของ pwd แต่จะไม่ทำงานกับคนอื่น
Walter Tross

แน่นอนคุณถูกคำถามที่ระบุว่าไฟล์จะอยู่ในไดเรกทอรีปัจจุบัน คุณหมายถึง "แต่ไม่ใช่กับผู้อื่น"
Arj

ผมหมายถึงจะไม่พบไฟล์นอกใต้ต้นไม้ไดเรกทอรีfind pwdเช่นหากคุณพยายามจะfind . -name ../existingFileล้มเหลว
Walter Tross

ก็พอแล้วใช่นี่จะถือว่าคุณต้องการพิมพ์เส้นทางแบบเต็มของไฟล์ใน cwd ของคุณ (ตามคำถามเดิม) หรือที่ใดก็ได้ในต้นไม้ cwd ของคุณ (ไม่ใช่คำถามเดิม)
Arj

1
#! /bin/bash

file="$@"
realpath "$file" 2>/dev/null || eval realpath $(echo $file | sed 's/ /\\ /g')

นี้จะทำให้การใช้ข้อบกพร่องของการเก็บไว้ในสคริปต์เปลือกrealpath fullpathตอนนี้คุณสามารถโทร:

$ cd && touch a\ a && rm A 2>/dev/null 
$ fullpath "a a"
/home/user/a a
$ fullpath ~/a\ a
/home/user/a a
$ fullpath A
A: No such file or directory.

มันแก้ปัญหาอะไร ->realpath "foo bar" /home/myname/foo barหากคุณไม่สามารถใส่ใจกับการอ้างอาร์กิวเมนต์ของบรรทัดคำสั่งได้นั่นไม่ใช่realpathความผิดของคุณ
ivan_pozdeev

เห็นด้วยเป็นเสื้อคลุมที่สะดวกกว่า
ShellFish

1

ทางเลือกอื่นในการรับพา ธ สัมบูรณ์ในRuby :

realpath() {ruby -e "require 'Pathname'; puts Pathname.new('$1').realpath.to_s";}

ทำงานโดยไม่มีอาร์กิวเมนต์ (โฟลเดอร์ปัจจุบัน) และไฟล์หรือพา ธ ของโฟลเดอร์แบบสัมพันธ์และแบบ Agument


0

ตอบด้วย Homebrew

realpathเป็นคำตอบที่ดีที่สุด แต่ถ้าคุณยังไม่ได้ติดตั้งคุณต้องเปิดใช้งานก่อนbrew install coreutilsซึ่งจะติดตั้งcoreutilsพร้อมฟังก์ชั่นที่ยอดเยี่ยมมากมาย การเขียนฟังก์ชั่นที่กำหนดเองและส่งออกมันเป็นงานและความเสี่ยงที่มากเกินไปสำหรับข้อผิดพลาดบางอย่างเช่นนี้นี่คือสองบรรทัด:

$ brew install coreutils
$ realpath your-file-name.json 

-1

เฮ้พวกฉันรู้ว่ามันเป็นด้ายเก่า แต่ฉันเพิ่งโพสต์สิ่งนี้เพื่ออ้างอิงถึงใครก็ตามที่เข้ามาเยี่ยมชมเช่นฉันนี้ หากฉันเข้าใจคำถามอย่างถูกต้องฉันคิดว่าlocate $filenameคำสั่ง มันจะแสดงเส้นทางที่แน่นอนของไฟล์ที่ให้มา แต่ถ้ามันมีอยู่


4
locateเป็นเครื่องมือในการค้นหาไฟล์ / เส้นทางตามชื่อ มันอาจทำงานได้ แต่อาจพบการจับคู่อื่น ๆ และอาจไม่พบไฟล์ที่มีอยู่โดยไม่ต้องเรียกupdatedbเป็นรูทก่อน
dhardy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.