определение пути к исходному сценарию оболочки

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

Я предполагаю, что у меня может не хватить удачи здесь, так как поиск источников вызывает выполнение команд в текущей оболочке, поэтому $0 по-прежнему является вызовом текущей оболочки, а не сценарием с исходным кодом. Моя лучшая мысль в настоящее время состоит в том, чтобы выполнить source $script $script , так что первый позиционный параметр содержит необходимую информацию. У кого-то есть лучший способ?

Чтобы быть ясным, я использую сценарий, а не его запуск:

 source foo.bash 

7 Solutions collect form web for “определение пути к исходному сценарию оболочки”

В tcsh , $_ в начале скрипта будет содержать местоположение, если файл был получен, а $0 содержит его, если он был запущен.

 #!/bin/tcsh set sourced=($_) if ("$sourced" != "") then echo "sourced $sourced[2]" endif if ("$0" != "tcsh") then echo "run $0" endif 

В Баше:

 #!/bin/bash called=$_ [[ $called != $0 ]] && echo "Script is being sourced" || echo "Script is being run" echo "\$BASH_SOURCE ${BASH_SOURCE[@]}" 

Я думаю, что вы можете использовать переменную $BASH_SOURCE . Он возвращает путь, который был выполнен:

 pbm@tauri ~ $ /home/pbm/a.sh /home/pbm/a.sh pbm@tauri ~ $ ./a.sh ./a.sh pbm@tauri ~ $ source /home/pbm/a.sh /home/pbm/a.sh pbm@tauri ~ $ source ./a.sh ./a.sh 

Итак, на следующем шаге мы должны проверить, является ли путь относительным или нет. Если это не относительное, все в порядке. Если это так, мы можем проверить путь с помощью pwd , $BASH_SOURCE с / и $BASH_SOURCE .

Для тщательности и ради искателей, вот что они делают … Это сообщество wiki, поэтому не стесняйтесь добавлять эквиваленты других оболочек (очевидно, $ BASH_SOURCE будет другим).

test.sh:

 #! /bin/sh called=$_ echo $called echo $_ echo $0 echo $BASH_SOURCE 

test2.sh:

 #! /bin/sh source ./test.sh 

Bash:

 $./test2.sh ./test2.sh ./test2.sh ./test2.sh ./test.sh $ sh ./test2.sh /bin/sh /bin/sh ./test2.sh ./test.sh 

тир

 $./test2.sh ./test2.sh ./test2.sh ./test2.sh $/bin/sh ./test2.sh /bin/sh /bin/sh ./test2.sh $ 

Zsh

 $ ./test2.sh ./test.sh ./test.sh ./test.sh $ zsh test.sh echo test.sh $ 

Замена $ BASH_SOURCE на $ DASH_SOURCE привела к тому же.

Это решение применяется только к bash, а не к tsh. Обратите внимание, что обычно ${BASH_SOURCE[0]} ответ ${BASH_SOURCE[0]} не будет работать, если вы попытаетесь найти путь из функции.

Я нашел, что эта строка всегда работает, независимо от того, был ли файл получен или запущен как сценарий.

 echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]} 

Если вы хотите следовать символическим ссылкам, используйте readlink по пути, который вы видите выше, рекурсивно или не рекурсивно.

Вот сценарий, чтобы попробовать его и сравнить с другими предлагаемыми решениями. Вызовите его как source test1/test2/test_script.sh или bash test1/test2/test_script.sh .

 # # Location: test1/test2/test_script.sh # echo $0 echo $_ echo ${BASH_SOURCE} echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]} cur_file="${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}" cur_dir="$(dirname "${cur_file}")" source "${cur_dir}/func_def.sh" function test_within_func_inside { echo ${BASH_SOURCE} echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]} } echo "Testing within function inside" test_within_func_inside echo "Testing within function outside" test_within_func_outside # # Location: test1/test2/func_def.sh # function test_within_func_outside { echo ${BASH_SOURCE} echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]} } 

Причина, по которой работает один лайнер, объясняется использованием переменной среды BASH_SOURCE и ее ассоциированной FUNCNAME .

BASH_SOURCE

Переменная массива, чьи члены являются исходными именами файлов, в которых определены соответствующие имена функций оболочки в переменной массива FUNCNAME. Функция оболочки $ {FUNCNAME [$ i]} определена в файле $ {BASH_SOURCE [$ i]} и вызывается из $ {BASH_SOURCE [$ i + 1]}.

имя_функции

Переменная массива, содержащая имена всех функций оболочки, находящихся в настоящее время в стеке вызовов выполнения. Элемент с индексом 0 – это имя любой текущей исполняемой функции оболочки. Самый нижний элемент (тот, который имеет самый высокий индекс) является «основным». Эта переменная существует только при выполнении функции оболочки. Присвоения функции FUNCNAME не влияют и возвращают статус ошибки. Если функция FUNCNAME не установлена, она теряет свои особые свойства, даже если она впоследствии будет сброшена.

Эта переменная может использоваться с BASH_LINENO и BASH_SOURCE. Каждый элемент FUNCNAME имеет соответствующие элементы в BASH_LINENO и BASH_SOURCE для описания стека вызовов. Например, $ {FUNCNAME [$ i]} вызывается из файла $ {BASH_SOURCE [$ i + 1]} при номере строки $ {BASH_LINENO [$ i]}. С помощью этой информации встроенный вызывающий объект отображает текущий стек вызовов.

[Источник: руководство Bash]

Это сработало для меня в bash, dash, ksh и zsh:

 if test -n "$BASH" ; then script=$BASH_SOURCE elif test -n "$TMOUT"; then script=${.sh.file} elif test -n "$ZSH_NAME" ; then script=${(%):-%x} elif test ${0##*/} = dash; then x=$(lsof -p $$ -Fn0 | tail -1); script=${x#n} else script=$0 fi echo $script 

Выход для этих оболочек:

 BASH source: ./myscript ZSH source: ./myscript KSH source: /home/pbrannan/git/theme/src/theme/web/myscript DASH source: /home/pbrannan/git/theme/src/theme/web/myscript BASH: ./myscript ZSH: ./myscript KSH: /home/pbrannan/git/theme/src/theme/web/myscript DASH: ./myscript 

Я попытался заставить его работать на csh / tcsh, но это слишком сложно; Я придерживаюсь POSIX.

Для оболочки bash я нашел ответ @Dennis Williamson наиболее полезным, но он не работал в случае sudo . Это делает:

 if ( [[ $_ != $0 ]] && [[ $_ != $SHELL ]] ); then echo "I'm being sourced!" exit 1 fi 

Фактически, «dirname $ 0» предоставит вам путь к скрипту, но вы должны немного его интерпретировать:

 $ cat bash0 #!/bin/bash echo \$0=$0 dirname $0 $ bash0 # "." appears in PATH right now. $0=./bash0 . $ ./bash0 $0=./bash0 . $ $PWD/bash0 $0=/home/00/bediger/src/ksh/bash0 /home/00/bediger/src/ksh $ $PWD/../ksh/bash0 $0=/home/00/bediger/src/ksh/../ksh/bash0 /home/00/bediger/src/ksh/../ksh $ ../ksh/bash0 $0=../ksh/bash0 ../ksh 

Вы должны подготовиться к работе ». как имя каталога при некоторых общих обстоятельствах. Я немного экспериментировал, так как я помню, что dirname встроен в ksh, делая вещи немного по-другому, когда «.» появляется в PATH.

  • Создание содержимого сложной переменной вручную
  • Почему мой tar в скрипте ведет себя иначе, чем использование tar вручную
  • Каждый пользователь получает свои собственные tty (ы)?
  • меньше команда с трубой
  • Разница между «trap -⁠-EXIT» и «trap-EXIT»
  • Метафора для концепции оболочки?
  • Как убить неактивных пользователей на Solaris?
  • проверьте, содержит ли строка символы
  • Тройка> (процесс) обрезает его stdout при записи файла
  • Как создать динамическую подстановку процессов на основе ввода (несколько FIFO)?
  • Поведение канала «|» в Linux с перенаправлением вывода «>»
  • Interesting Posts
    Linux и Unix - лучшая ОС в мире.