2013-07-10 21 views
61

Tôi đã viết một tập lệnh bash có một tệp đầu vào làm đối số và đọc nó.
Tệp này chứa một số đường dẫn (liên quan đến vị trí của nó) với các tệp bổ sung được sử dụng.Làm cách nào để lấy thư mục tuyệt đối của tệp trong bash?

Tôi muốn tập lệnh chuyển đến thư mục chứa tệp đầu vào, để thực hiện các lệnh khác.

Vì vậy, làm cách nào để nhận thư mục (và chỉ thư mục) từ tệp đầu vào? (Trong Linux.)

+0

Bạn có đưa ra đường dẫn đầy đủ đến tập tin đầu vào hay chỉ là con đường tương đối so với hiện tại thư mục làm việc? – dmh

+0

dhm: đầu vào cung cấp đường dẫn tương đối, tôi muốn đường dẫn tuyệt đối * trừ * tên tệp. – BobMcGee

Trả lời

121

Để có được con đường sử dụng đầy đủ:

readlink -f relative/path/to/file 

Để có được thư mục của một tập tin:

dirname relative/path/to/file 

Bạn cũng có thể kết hợp hai:

dirname $(readlink -f relative/path/to/file) 

Nếu readlink -f không khả dụng trên hệ thống của bạn, bạn có thể sử dụng điều này:

function myreadlink() { 
    (
    cd $(dirname $1)   # or cd ${1%/*} 
    echo $PWD/$(basename $1) # or echo $PWD/${1##*/} 
) 
} 

Lưu ý rằng nếu bạn chỉ cần di chuyển đến một thư mục của một tập tin quy định như một đường dẫn tương đối, bạn không cần phải biết đường dẫn tuyệt đối, một đường dẫn tương đối là hoàn toàn hợp pháp, vì vậy chỉ cần sử dụng:

cd $(dirname relative/path/to/file) 

nếu bạn muốn quay trở lại (trong khi kịch bản đang chạy) đến đường dẫn gốc, sử dụng pushd thay vì cd, và popd khi bạn đang thực hiện.

+10

Lưu ý rằng 'readlink -f' không hoạt động trên OS X, thật không may. –

+0

Tôi không muốn toàn bộ con đường, tôi chỉ muốn thư mục. Nhưng điều này cung cấp đủ để có ích: readlink -f relativeFileLocation | xargs dirname – BobMcGee

+1

@EmilSit: bạn đúng - nguyên bản. Nhưng bạn có thể 'brew install coreutils' để lấy nó. http://stackoverflow.com/a/4031502/1022967. – mpettis

0

tôi đã được sử dụng readlink -f hoạt động trên Linux

nên

FULL_PATH=$(readlink -f filename) 
DIR=$(dirname $FULL_PATH) 

PWD=$(pwd) 

cd $DIR 

#<do more work> 

cd $PWD 
+3

không sử dụng tên biến hoa trong Bash, một ngày nào đó sẽ đụng độ với các biến đã tồn tại ... oh, và ngày này là bây giờ: bạn có biết biến 'PWD' đã tồn tại trong Bash một giá trị của nó thực sự là thư mục hiện tại không? Và sử dụng nhiều dấu ngoặc kép nữa. –

+0

Cảm ơn rất nhiều, tôi sẽ ghi nhớ điều đó. –

17

Hãy xem man page của realpath, tôi sử dụng đó và một cái gì đó như:

CONTAININGDIR = $ (đường dẫn thực $ {FILEPATH%/*})

to làm những gì có vẻ như bạn đang cố gắng làm.

+0

realpath làm một kỳ lạ với tôi, nơi nó giải quyết các liên kết tượng trưng của các thư mục tương đối –

+0

Cảm ơn! Làm việc cho tôi trên Mac OS –

1

Thử sản phẩm thư viện Bash mới của chúng tôi realpath-lib qua GitHub mà chúng tôi đã cung cấp cho cộng đồng để sử dụng miễn phí và không bị cản trở. Nó sạch sẽ, đơn giản và được tài liệu hóa nên rất tuyệt vời để học hỏi. Bạn có thể làm:

get_realpath <absolute|relative|symlink|local file path> 

Chức năng này là cốt lõi của thư viện:

if [[ -f "$1" ]] 
then 
    # file *must* exist 
    if cd "$(echo "${1%/*}")" &>/dev/null 
    then 
     # file *may* not be local 
     # exception is ./file.ext 
     # try 'cd .; cd -;' *works!* 
     local tmppwd="$PWD" 
     cd - &>/dev/null 
    else 
     # file *must* be local 
     local tmppwd="$PWD" 
    fi 
else 
    # file *cannot* exist 
    return 1 # failure 
fi 

# reassemble realpath 
echo "$tmppwd"/"${1##*/}" 
return 0 # success 

} 

Đó là Bash 4+, không đòi hỏi bất kỳ phụ thuộc và cũng cung cấp get_dirname, get_filename, get_stemname và validate_path.

0

Sự cố với câu trả lời ở trên đi kèm với tệp nhập bằng "./" như "./my-file.txt"

Cách giải quyết (nhiều):

myfile="./somefile.txt" 
    FOLDER="$(dirname $(readlink -f "${ARG}"))" 
    echo ${FOLDER} 
5

này sẽ làm việc cho cả hai tập tin và thư mục:

absPath(){ 
    if [[ -d "$1" ]]; then 
     cd "$1" 
     echo "$(pwd -P)" 
    else 
     cd "$(dirname "$1")" 
     echo "$(pwd -P)/$(basename "$1")" 
    fi 
} 
0
$cat abs.sh 
#!/bin/bash 
echo "$(cd "$(dirname "$1")"; pwd -P)" 

Một số giải thích:

  1. Kịch bản này có được đường dẫn tương đối làm đối số "$1"
  2. Sau đó, chúng tôi nhận dirname phần của con đường đó (bạn có thể vượt qua một trong hai dir hoặc tập tin vào kịch bản này): dirname "$1"
  3. Sau đó chúng tôi cd "$(dirname "$1"); vào dir tương đối này
  4. pwd -P và nhận được đường dẫn tuyệt đối. Các tùy chọn -P sẽ tránh symlink
  5. Là bước cuối cùng chúng tôi echo

Sau đó chạy script của bạn:

abs.sh your_file.txt