Tìm vị trí của tập lệnh shell có nguồn gốc


8

Có thể là một kịch bản shell có nguồn gốc biết vị trí của nó? Tôi đã đọc xác định đường dẫn đến shell script có nguồn gốc nhưng câu trả lời tập trung vào bashtcshvà thất bại nếu một vỏ POSIX được sử dụng. $0cũng không phải là giải pháp và mang lại kết quả sai .

Một giải pháp không cần phải đáng tin cậy 100%. Không chắc là đường dẫn chứa cứng hoặc liên kết tượng trưng.

# sourcing the script should yield the absolute path to the script
. somedir/thescript

# within “thescript”
-> /tmp/foo/bar/somedir

Một số nền tảng: Tập lệnh là một phần của ứng dụng hiện có chứa hàng tá nhị phân trong một binthư mục ở một vị trí đã biết (thay đổi theo kiến ​​trúc) so với tập lệnh có nguồn gốc. Để sử dụng ứng dụng, người dùng sẽ cung cấp tập lệnh sắp xếp binthư mục vào PATH, vì vậy các nhị phân của ứng dụng có thể dễ dàng được gọi trong shell hiện tại (bất kỳ shell nào có thể).


Vui lòng kiểm tra một lần liên kết này có thể là những gì bạn đang tìm kiếm paste.ubfox.com/6242655
Rahul Patil

@RahulPatil Điều đó chỉ hoạt động trên bash và rất không khả thi.
Marco

1
Tôi khá chắc chắn rằng câu trả lời là không. Bạn chỉ tìm thấy các phương thức dành riêng cho shell vì không có phương thức di động. Bạn cần cái này để làm gì? Bạn có thể nói với người dùng kịch bản để làm một cái gì đó khác biệt . /path/to/scriptnhư MARCO_DIR=/path/to; . $MARCO_DIR/scripthay eval "$(/path/to/script)"không? @RahulPatil BASH_SOURCErõ ràng là cụ thể cho bash.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles Như tôi đã nói, nó không cần phải rất mạnh mẽ. Nhưng tôi đã không tìm thấy một cách mà thậm chí từ xa hoạt động trong các trường hợp đơn giản nhất trong vỏ POSIX. (Vì vậy, giải pháp cho thời điểm hiện tại là việc sử dụng ứng dụng này đòi hỏi phải có một trong các trình bao được hỗ trợ.) Hãy thoải mái đăng bài không có câu trả lời nếu đó câu trả lời.
Marco

@Gilles Thay đổi cách thiết lập ứng dụng không phải là một tùy chọn. Nó sẽ phá vỡ các cài đặt. Đó là lý do tại sao tôi muốn làm cho kịch bản mạnh mẽ hơn mà không thay đổi cách gọi. Cuối cùng, nó chỉ thiết lập PATH, vì vậy nếu kịch bản thất bại, dự phòng là tìm các nhị phân và thêm đường dẫn của chúng vào môi trường.
Marco

Câu trả lời:


9

Vị trí của tập lệnh có nguồn gốc là không có sẵn trừ khi bạn đang sử dụng trình bao cung cấp các phần mở rộng cho đặc tả POSIX. Bạn có thể kiểm tra điều này với đoạn mã sau:

env -i PATH=/usr/bin:/bin sh -c '. ./included.sh' | grep included

nơi included.shchứa

echo "$0"
set

Trong bash, tên của tập lệnh có nguồn gốc là trong $BASH_SOURCE. Trong zsh (trong chế độ tương thích zsh, không phải ở chế độ tương thích sh hoặc ksh), nó ở $0(lưu ý rằng trong một hàm, $0là tên hàm thay thế). Trong pdksh và dash, nó không có sẵn. Trong ksh93, phương pháp này không tiết lộ giải pháp, nhưng đường dẫn đầy đủ đến tập lệnh được bao gồm có sẵn như ${.sh.file}.

Nếu yêu cầu bash hoặc ksh93 hoặc zsh là đủ tốt, bạn có thể sử dụng đoạn mã này:

if [ -n "$BASH_SOURCE" ]; then
  this_script=$BASH_SOURCE
elif [ -n "$ZSH_VERSION" ]; then
  setopt function_argzero
  this_script=$0
elif eval '[[ -n ${.sh.file} ]]' 2>/dev/null; then
  eval 'this_script=${.sh.file}'
else
  echo 1>&2 "Unsupported shell. Please use bash, ksh93 or zsh."
  exit 2
fi

Bạn có thể thử đoán vị trí của tập lệnh bằng cách xem tập tin nào shell đã mở. Về mặt thực nghiệm, điều này dường như hoạt động với dash và pdksh nhưng không phải với bash hoặc ksh93 mà ít nhất là đối với một đoạn script ngắn đã đóng tệp script vào thời điểm chúng thực hiện để thực thi nó.

  open_file=$(lsof -F n -p $$ | sed -n '$s/^n//p')
  if [ -n "$open_file" ]; then
    # best guess: $open_file is this script
  fi

Tập lệnh có thể không phải là tập tin có bộ mô tả được đánh số cao nhất nếu tập lệnh có nguồn gốc bên trong một tập lệnh phức tạp đang phát với các chuyển hướng. Bạn có thể muốn lặp qua các tệp đang mở. Điều này không được đảm bảo để làm việc nào. Cách đáng tin cậy duy nhất để xác định vị trí tập lệnh có nguồn gốc là sử dụng bash, ksh93 hoặc zsh.


Nếu bạn có thể thay đổi giao diện, thì thay vì tìm nguồn cung cấp cho tập lệnh của bạn, hãy để tập lệnh của bạn in ra một đoạn mã được chuyển đến evaltrong trình gọi. Đây là những gì các kịch bản để thiết lập các biến môi trường thường làm. Nó cho phép tập lệnh của bạn được viết độc lập với sự mơ hồ về cấu hình shell và shell của trình gọi.

#!/bin/sh
FOO_DIR=$(dirname -- "$0")
cat <<EOF
FOO_DIR='$(printf %s "$FOO_DIR" | sed "s/'/'\\''/g")'
PATH="\$PATH:$FOO_DIR/bin";
export FOO_DIR PATH
EOF

Trong người gọi: eval "`/path/to/setenv`"


0

Thêm vào câu trả lời của Gilles, bạn CÓ THỂ có được tập lệnh shell ( if $0 = ash) thông qua /proc/$$ interface. Tôi không biết chính xác điều này như thế nào, nhưng /proc/$$/fd/11dường như luôn luôn chỉ ra biểu tượng này với tro của BusyBox.

Cung cấp điều này như một câu trả lời tiềm năng cho những người đi qua trang này (tôi cũng vậy).

Câu trả lời cuối cùng đã bị xóa - vì vậy, yêu cầu của tôi đối với hoạt động này đã được thử nghiệm trên 4 nền tảng CT khác nhau (x86, ARM, XLP và powerpc). Tất cả đưa ra cùng một câu trả lời của fd / 11. Một đường dẫn từ /proc/$$/fd/11mang lại kịch bản của tôi.

Andy

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.