Tham khảo một tệp trong cùng thư mục của tập lệnh được tìm thấy trong $ PATH


33

Tôi có một tập tin bash script, được đặt trong một số thư mục được thêm vào $ PATH để tôi có thể gọi tập lệnh từ bất kỳ thư mục nào.

Có một tệp văn bản khác trong cùng thư mục với tập lệnh. Tôi tự hỏi làm thế nào để tham khảo các tập tin văn bản trong kịch bản?

Ví dụ: nếu tập lệnh chỉ để xuất nội dung của tệp văn bản, cat textfilesẽ không hoạt động, vì khi gọi tập lệnh từ một thư mục khác, không tìm thấy tệp văn bản.



Câu hỏi này trả lời làm thế nào để có được đường dẫn tập tin bash đáng tin cậy, tôi đã thêm nó vào đường dẫn của mình: stackoverflow.com/q/4774054/1695680
ThorSummoner 16/07/2015

Câu trả lời:


24

Chúng nên hoạt động như nhau, miễn là không có liên kết tượng trưng (trong phần mở rộng đường dẫn hoặc chính tập lệnh):

  • MYDIR="$(dirname "$(realpath "$0")")"

  • MYDIR="$(dirname "$(which "$0")")"

  • Một phiên bản hai bước của bất kỳ điều nào ở trên:

    MYSELF="$(realpath "$0")"

    MYDIR="${MYSELF%/*}"

Nếu có một liên kết tượng trưng trên đường đến tập lệnh của bạn, thì whichsẽ cung cấp câu trả lời không bao gồm độ phân giải của liên kết đó. Nếu realpathkhông được cài đặt theo mặc định trên hệ thống của bạn, bạn có thể tìm thấy nó ở đây .

[EDIT]: Vì dường như realpathkhông có lợi thế nào so với readlink -f đề xuất của Caleb , có lẽ tốt hơn là sử dụng cái sau. Kiểm tra thời gian của tôi cho thấy nó thực sự nhanh hơn.


Không vấn đề gì. Bằng cách nào đó realpathđến từ hệ thống của bạn. (Đối với những người khác không có nó, bạn có thể sử dụngreadlink -f
Caleb

@Caleb Thật ra tôi nghĩ nó thuộc về tập hợp các tiện ích GNU tiêu chuẩn (coreutils), nhưng tôi có thể thấy bây giờ nó là một gói riêng biệt .
rozcietrzewiacz

@rozcietrzewiacz realpathcó từ trước đó readlink -f(và thậm chí readlink, IIRC) đã có trong lõi core GNU (có một số công cụ tương tự xung quanh. readlink -fcuối cùng đã trở thành tiêu chuẩn thực tế); realpathchỉ được giữ cho tương thích với các tập lệnh vẫn sử dụng nó.
Gilles 'SO- ngừng trở nên xấu xa'

Whats lợi thế $(dirname "$(which "$0")")hơn $(dirname $0)whichkhông còn hiện tại? Nó không giống nhau sao?
UlfR

readlink -fdường như không hoạt động trên Mac OS X 10.11.6, nhưng realpathhoạt động vượt trội .
Grav

9

Hệ thống của tôi không có realpathnhư đề xuất của rozcietrzewiacz .

Bạn có thể thực hiện điều này bằng cách sử dụng readlinklệnh. Ưu điểm của việc sử dụng phương pháp này để phân tích cú pháp whichhoặc các giải pháp khác là ngay cả khi một phần của đường dẫn hoặc tên tệp được thực thi là một liên kết tượng trưng, ​​bạn sẽ có thể tìm thấy thư mục chứa tệp thực tế.

MYDIR="$(dirname "$(readlink -f "$0")")"

Tệp văn bản của bạn sau đó có thể được đọc thành một biến như thế này:

TEXTFILE="$(<$MYDIR/textfile)"

@rozcietrzewiacz: Tôi thực sự không đề cập đến chỉ whichđề nghị của bạn . Giải pháp bình thường cho việc này liên quan đến chỉ dirnamehoặc kết hợp cdpwdtrong một lớp con. Readlink có lợi thế ở đây. realpathDường như khá nhiều chỉ là một bọc cho readlink -fdù sao.
Caleb

Tôi không biết làm thế nào realpathkhác với readlink -f. Tôi chỉ có thể thấy nó mang lại cho tôi kết quả tương tự (trái ngược với which).
rozcietrzewiacz

Hãy nhớ rằng readlink -f(từ GNU coreutils) KHÔNG yêu cầu phần tử cuối cùng của đường dẫn tồn tại readlink -e, nhưng không được hỗ trợ bởi busybox readlink, nó bắt chước hành vi -etrong -ftùy chọn của chúng .
dragon788

8

$0trong tập lệnh sẽ là đường dẫn đầy đủ đến tập lệnh và dirnamesẽ lấy một đường dẫn đầy đủ và chỉ cung cấp cho bạn thư mục, vì vậy bạn có thể làm điều này để catfile:

$ cat "$(dirname -- "$0")/textfile"

Mặc dù điều này dường như hoạt động mà không có realpath $0, bạn đã sai khi nói rằng " $0trong kịch bản sẽ là đường dẫn đầy đủ đến kịch bản".
rozcietrzewiacz

@roz Theo cách nào?
Michael Mrozek

1
$0là lệnh khi nó được chạy, có thể là ví dụ ../script.sh.
rozcietrzewiacz

Vì vậy, thực sự $(dirname "$0")trả về đường dẫn tương đối cho tập lệnh, như là một phần của lệnh được gọi - không phải là đường dẫn tuyệt đối. Điều này có thể dẫn đến các vấn đề trong các kịch bản thay đổi thư mục trong khi chạy.
rozcietrzewiacz

@roz À, thú vị. Vì vậy, tôi đoán nó sẽ không gây ra vấn đề gì ở đây vì anh ta gọi một cái gì đó trên con đường bằng tên, nhưng nó sẽ phá vỡ những thứ khác. Cảm ơn
Michael Mrozek

4

Bạn có thể đặt phần này ở đầu tập lệnh của bạn:

cd "${BASH_SOURCE%/*}" || exit

Biến bash nội bộ BASH_SOURCE thực sự là một mảng các tên đường dẫn. Nếu bạn mở rộng chuỗi dưới dạng một chuỗi đơn giản, ví dụ: "$ BASH_SOURCE", bạn sẽ nhận được phần tử đầu tiên, đó là tên đường dẫn của hàm hoặc tập lệnh hiện đang thực thi.

Nguồn: http://mywiki.wooledge.org/BashFAQ/028


2

Tôi đã thử những thứ này và realpath không làm việc cho tôi. Giải pháp tôi đã thực hiện là:

SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )

Mà đã làm việc tốt cho đến nay. Tôi muốn biết nếu có bất kỳ vấn đề tiềm năng với cách tiếp cận.


1
Tốt, nhưng không theo liên kết tượng trưng. Hãy thử điều này:SCRIPT_DIR="$( cd "$(dirname "$( readlink -f ${BASH_SOURCE[0]} )")" >/dev/null 2>&1 && pwd)"
OronNavon

1

Tôi sử dụng:

#! /bin/sh -
dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P) || exit
dosomethingwith "${dir%/}/some-file"

Đó là POSIX và sẽ hoạt động miễn là tên thư mục $0không kết thúc bằng các ký tự dòng mới, không -$CDPATHkhông được đặt (và có thể một vài trường hợp góc khác nếu tập lệnh không được tra cứu $PATH).


0

Tôi luôn luôn sử dụng whichđể tìm đường dẫn đầy đủ của một tệp thực thi từ PATH. Ví dụ:

which python

Nếu bạn kết hợp điều này với dirnamelệnh thì bạn nhận được:

wp=`which python`
dn=`dirname $wp`
ls $dn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.