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.sh
chứ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, $0
là 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 eval
trong 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`"