Как узнать имя файла скрипта в скрипте Bash? - PullRequest
521 голосов
/ 10 октября 2008

Как определить имя файла сценария Bash внутри самого сценария?

Например, если мой скрипт находится в файле runme.sh, то как мне сделать так, чтобы он отображал сообщение «Вы запускаете runme.sh» без жесткого кодирования?

Ответы [ 22 ]

548 голосов
/ 10 октября 2008
me=`basename "$0"`

Для чтения символической ссылки 1 , что обычно не то, что вам нужно (обычно вы не хотите путать пользователя таким образом), попробуйте:

me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"

IMO, это даст непонятный результат. "Я запустил foo.sh, но он говорит, что я запускаю bar.sh !? Должно быть, это ошибка!" Кроме того, одной из целей получения символических ссылок с разными именами является предоставление различных функциональных возможностей в зависимости от имени, которое оно называется (например, gzip и gunzip на некоторых платформах).


1 То есть, чтобы разрешить символические ссылки таким образом, чтобы при выполнении пользователем foo.sh, который на самом деле является символической ссылкой на bar.sh, вы хотели использовать разрешенное имя bar.sh вместо foo.sh .

224 голосов
/ 28 августа 2010
# ------------- SCRIPT ------------- #
<code>
#!/bin/bash

echo
echo "# arguments called with ---->  ${@}     "
echo "# \$1 ---------------------->  $1       "
echo "# \$2 ---------------------->  $2       "
echo "# path to me --------------->  ${0}     "
echo "# parent path -------------->  ${0%/*}  "
echo "# my name ------------------>  ${0##*/} "
echo
exit
</code>
# ------------- CALLED ------------- #

# Notice on the next line, the first argument is called within double, 
# and single quotes, since it contains two words

<strong>$  /misc/shell_scripts/check_root/show_parms.sh "'hello there'" "'william'"</strong>

# ------------- RESULTS ------------- #

# arguments called with --->  'hello there' 'william'
# $1 ---------------------->  'hello there'
# $2 ---------------------->  'william'
# path to me -------------->  /misc/shell_scripts/check_root/show_parms.sh
# parent path ------------->  /misc/shell_scripts/check_root
# my name ----------------->  show_parms.sh

# ------------- END ------------- #
178 голосов
/ 12 марта 2009

С bash> = 3 следующие работы:

$ ./s
0 is: ./s
BASH_SOURCE is: ./s
$ . ./s
0 is: bash
BASH_SOURCE is: ./s

$ cat s
#!/bin/bash

printf '$0 is: %s\n$BASH_SOURCE is: %s\n' "$0" "$BASH_SOURCE"
62 голосов
/ 10 октября 2008

Если в имени скрипта есть пробелы, более надежный способ - использовать "$0" или "$(basename "$0")" - или в MacOS: "$(basename \"$0\")". Это предотвращает искажение или интерпретацию имени любым способом. Как правило, рекомендуется всегда заключать в кавычки имена переменных в оболочке.

60 голосов
/ 15 июня 2011

$BASH_SOURCE дает правильный ответ при поиске сценария.

Однако этот путь включает путь, чтобы получить только имя файла сценария, используйте:

$(basename $BASH_SOURCE) 
24 голосов
/ 10 октября 2008

Если вы хотите без пути, тогда вы бы использовали ${0##*/}

19 голосов
/ 10 октября 2008

Чтобы ответить Крис Конвей , в Linux (как минимум) вы бы сделали это:

echo $(basename $(readlink -nf $0))

readlink печатает значение символической ссылки. Если это не символическая ссылка, печатается имя файла. -n говорит не печатать новую строку. -f говорит, что следует полностью перейти по ссылке (если символическая ссылка была ссылкой на другую ссылку, она также разрешит эту ссылку).

13 голосов
/ 01 сентября 2014

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

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

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

Причина, по которой работает однострочник, объясняется использованием переменной окружения 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]

11 голосов
/ 12 марта 2009

Эти ответы верны для тех случаев, в которых они указаны, но проблема остается, если вы запускаете скрипт из другого скрипта, используя ключевое слово «source» (чтобы он выполнялся в той же оболочке). В этом случае вы получаете $ 0 вызывающего скрипта. И в этом случае я не думаю, что возможно получить название самого сценария.

Это крайний случай, и к нему не следует относиться серьезно. Если вы запустите скрипт из другого скрипта напрямую (без 'source'), будет работать $ 0.

8 голосов
/ 05 февраля 2018

Так как некоторые комментарии спрашивают о имени файла без расширения, вот пример, как это сделать:

FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}

Наслаждайтесь!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...