Tìm đường dẫn tuyệt đối từ một tập lệnh


10

Trong một kịch bản tôi nhận được trong $0đường dẫn tương đối có thể đến nó. Để chuyển đổi nó thành tuyệt đối tôi đã tìm thấy giải pháp này mà tôi không hiểu:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

Vấn đề của tôi là sự kỳ diệu bên trong ${0%/*}${0##*/}. Có vẻ như cái trước trích xuất dirname và cái sau trích xuất tên tệp, tôi không hiểu làm thế nào.


2
Điều đó sử dụng mở rộng tham số, nhưng nó không làm việc cho tôi. Nếu tập lệnh của bạn sẽ chỉ được sử dụng trên Linux, bạn có thể sử dụng readlink -f $0để có được đường dẫn chính tắc.
Shawn J. Goff

1
@Shawn: 1 bình luận tuyệt vời vì bạn đã đưa ra suy nghĩ đúng: "Điều đó sử dụng mở rộng tham số, nhưng nó không hoạt động với tôi". Việc dirnamesử dụng là hữu ích ở đây.
D4RIO

mywiki.wooledge.org/BashFAQ/028cyberciti.biz/faq/NH nói BASH_SOURCElà tốt hơn $0, vì $0cung cấp cho người dùng gõ lệnh, có thể không phải là tập lệnh hiện đang thực thi.
Joel Purra

Câu trả lời:


8

Định nghĩa:

${string%substring} xóa trận đấu ngắn nhất $substringtừ cuối $string.

${string##substring}xóa trận đấu dài nhất $substringtừ đầu $string.

Ví dụ của bạn:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

${0%/*} xóa mọi thứ sau dấu gạch chéo cuối cùng, cung cấp cho bạn tên thư mục của tập lệnh (có thể là đường dẫn tương đối).

${0##*/} xóa mọi thứ cho đến dấu gạch chéo cuối cùng, chỉ cho bạn tên của tập lệnh.

Vì vậy, lệnh này thay đổi thành thư mục của tập lệnh và nối thư mục làm việc hiện tại (được cung cấp bởi $PWD) và tên của tập lệnh cung cấp cho bạn đường dẫn tuyệt đối.

Để xem những gì đang xảy ra hãy thử:

echo ${0%/*}
echo ${0##*/}

Thêm dấu ngoặc kép xung quanh tất cả các mở rộng biến để đối phó với (hầu hết tất cả) tên tệp có chứa các ký tự đặc biệt shell.
Gilles 'SO- ngừng trở nên xấu xa'

10

Shawn đã có giải pháp đơn giản nhất : readlink -f $0. Nếu bạn muốn chắc chắn xử lý các tên tệp lạ, bạn có thể sử dụng:

absolute_path_x="$(readlink -fn -- "$0"; echo x)"
absolute_path="${absolute_path_x%x}"

Tài liệu


1
Tốt để xem dòng mới cuối cùng xử lý chính xác. Thật không may readlink -fnlà cụ thể cho Linux, NetBSD và OpenBSD.
Gilles 'SO- ngừng trở nên xấu xa'

4

Đây là một cách an toàn hơn và dễ đọc hơn để làm công việc này:

abspath=$(unset CDPATH && cd "$(dirname "$0")" && echo $PWD/$(basename "$0"))

Ghi chú:

  • Nếu $0là một tên tệp trần không có đường dẫn trước, tập lệnh gốc sẽ thất bại nhưng tập lệnh được đưa ra ở đây sẽ hoạt động. (Không phải là vấn đề với $0nhưng có thể trong các ứng dụng khác.)
  • Cách tiếp cận sẽ thất bại nếu đường dẫn đến tệp không thực sự tồn tại. (Không phải là vấn đề với $0, nhưng có thể trong các ứng dụng khác.)
  • Điều unsetnày rất cần thiết nếu người dùng của bạn có thể đã CDPATHthiết lập.
  • Không giống như readlink -fhoặc realpath, điều này sẽ hoạt động trên các phiên bản Unix không phải của Linux (ví dụ: Mac OS X).

2

Nếu bạn muốn tìm hiểu Mở rộng thông số Shell, bạn có thể đọc nó từ đây , nhưng Mở rộng không phải lúc nào cũng là một lựa chọn tốt. Trong trường hợp này, hầu hết mọi hệ thống giống như Unix đều có 2 tiện ích tốt:

basename
dirname

Cái đầu tiên sẽ trích xuất tên tệp, trong khi cái thứ hai sẽ trích xuất đường dẫn, vì vậy, nếu bạn có $ 0, hãy nói:

dirname $0

Và bạn sẽ có được con đường.

Chúc mừng


dirname có thể trả về các đường dẫn tương đối
quang vòng

0

Giới thiệu pwd, bash dựng sẵn. Cũng được tìm thấy trong gói GNU coreutils.

$ sh ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
$0: ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
cheeky binary from /home/jaroslav/tmp (/home/jaroslav/tmp)

$ cat /home/jaroslav/tmp/somewhere.sh

abs=$( cd `dirname "$0"` ; pwd -P)
absBin=$( cd `dirname "$0"` ; /bin/pwd -P)
echo \$0: $0
echo cheeky binary from $abs \($absBin\)
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.