Найти местоположение исходного сценария оболочки


8

Возможно ли, что исходный сценарий оболочки знает свое местоположение? Я прочитал определение пути к соерседу сценарию оболочки , но ответы сосредоточиться на bashи tcshи потерпеть неудачу , если используется POSIX оболочка. $0также не является решением и дает неправильные результаты .

Решение не должно быть на 100% надежным. Маловероятно, что путь содержит жесткие или символические ссылки.

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

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

Немного предыстории: сценарий является частью существующего приложения, содержащего десятки двоичных файлов в binкаталоге в известном месте (зависит от архитектуры) относительно исходного сценария. Чтобы использовать приложение, пользователь создает сценарий, который добавляет binкаталог в каталог PATH, поэтому двоичные файлы приложения могут быть легко вызваны в текущей оболочке (какой бы она ни была).


Пожалуйста, однажды проверьте, что эта ссылка может быть тем, что вы ищете paste.ubuntu.com/6242655
Рахул Патил

@RahulPatil Это работает только на bash и крайне непереносимо.
Марко

1
Я уверен, что ответ - нет. Вы нашли только специфичные для оболочки методы, потому что нет переносимого метода. Для чего вам это нужно? Можете ли вы сказать пользователям скрипта что-то отличное от . /path/to/scriptтаких как MARCO_DIR=/path/to; . $MARCO_DIR/scriptили eval "$(/path/to/script)"? @RahulPatil BASH_SOURCEявно относится к bash.
Жиль "ТАК - перестань быть злым"

@ Жиль Как я уже сказал, это не должно быть очень крепким. Но я не нашел способа, который бы даже отдаленно работал в простейших случаях в оболочке POSIX. (Таким образом, решение до поры до времени является то , что использование этого приложения требуется одна из поддерживаемых оболочек.) Вы можете разместить «нет ...» как ответ , если это является ответом.
Марко

@Gilles Изменение способа настройки приложения - не вариант. Это сломало бы установки. Вот почему я хотел бы сделать скрипт более устойчивым, не меняя способ его вызова. В конце концов, он просто устанавливает PATH, поэтому, если скрипт завершается неудачей, запасной вариант - найти двоичные файлы и добавить их путь в среду.
Марко

Ответы:


9

Расположение исходного сценария недоступно, если вы не используете оболочку, которая предлагает расширения для спецификации POSIX. Вы можете проверить это с помощью следующего фрагмента:

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

где included.shсодержится

echo "$0"
set

В bash имя исходного сценария находится в $BASH_SOURCE. В zsh (в режиме совместимости с zsh, а не в режиме совместимости с sh или ksh) он находится в $0(обратите внимание, что в $0функции вместо этого используется имя функции). В pdksh и dash он недоступен. В ksh93 этот метод не раскрывает решение, но полный путь к включенному сценарию доступен как ${.sh.file}.

Если вам требуется bash, ksh93 или zsh, вы можете использовать этот фрагмент:

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

Вы можете попытаться угадать местоположение скрипта, посмотрев, какие файлы открыта оболочкой. Экспериментально это работает с dash и pdksh, но не с bash или ksh93, которые, по крайней мере для короткого скрипта, закрыли файл скрипта к тому времени, когда им удалось его выполнить.

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

Сценарий может не являться файлом с дескриптором с наибольшим номером, если сценарий получен из сложного сценария, который воспроизводит перенаправления. Вы можете циклически просматривать открытые файлы. Это не гарантировано работать в любом случае. Единственный надежный способ найти исходный скрипт - это использовать bash, ksh93 или zsh.


Если вы можете изменить интерфейс, то вместо того, чтобы использовать свой сценарий, пусть ваш сценарий распечатает фрагмент оболочки, который будет передан evalвызывающей стороне. Это то, что обычно делают скрипты для установки переменных среды. Это позволяет вашему сценарию быть написанным независимо от капризов оболочки вызывающего абонента и конфигурации оболочки.

#!/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

В звонилке: eval "`/path/to/setenv`"


0

Добавив к ответу Жиля, вы МОЖЕТЕ получить сценарий оболочки ( if $0 = ash) через /proc/$$ interface. Я не знаю, насколько это точно, но, /proc/$$/fd/11кажется, всегда указывает на this_script с пеплом BusyBox.

Предоставляя это как потенциальный ответ тем, кто сталкивался с этой страницей (как я сделал).

Последний ответ был удален - так что мои претензии к этой работе проверены на 4 разных платформах HW (x86, ARM, XLP и powerpc). Все дают один и тот же ответ FD / 11. Ссылка на чтение из /proc/$$/fd/11приводит к моему сценарию.

Энди

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.