it-swarm.com.ru

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

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

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

490
Ma99uS
me=`basename "$0"`

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

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

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

518
Tanktalus
 # ------------- СЦЕНАРИЙ ------------- # 

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

 # ---------- --- CALLED ------------- # 

 # Обратите внимание, что на следующей строке первый аргумент вызывается в двойных, 
 # И одинарных кавычках, поскольку он содержит два слова 

 $ /misc/Shell_scripts/check_root/show_parms.sh "'здравствуй'" "" Уильям "

 # --------- ---- РЕЗУЛЬТАТЫ ------------- # 

 # Аргументы, вызываемые с помощью ---> 'hello there' 'william' 
 # $ 1 ----- -----------------> «Привет!» 
 # $ 2 ----------------------> 'william' 
 # путь ко мне --------------> /misc/Shell_scripts/check_root/show_parms.sh
# родительский путь --------- ----> /misc/Shell_scripts/check_root
# мое имя -----------------> show_parms.sh 

 # ----- -------- КОНЕЦ ------------- #
212
Bill Hernandez

С 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"
172
Dimitre Radoulov

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

60
Josh Lee

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

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

$(basename $BASH_SOURCE) 
58
Zainka

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

21
Mr. Muskrat

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

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

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

19
Travis B. Hartwell

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

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

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

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

BASH_SOURCE

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

Имя_функции

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

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

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

13
gkb0986

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

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

11
Jim Dodd

Re: ответ Tanktalus (принятый) выше, более чистый способ заключается в использовании:

me=$(readlink --canonicalize --no-newline $0)

Если ваш скрипт был получен из другого скрипта bash, вы можете использовать:

me=$(readlink --canonicalize --no-newline $BASH_SOURCE)

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

8
simon

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

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

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

7
Simon Mattes

если ваш вызов сценария Shell, как 

/home/mike/runme.sh

$ 0 - полное имя

 /home/mike/runme.sh

базовое имя $ 0 получит базовое имя файла

 runme.sh

и вам нужно поместить это основное имя в переменную, такую ​​как

filename=$(basename $0)

и добавьте свой дополнительный текст 

echo "You are running $filename"

так что ваши сценарии как 

/home/mike/runme.sh
#!/bin/bash 
filename=$(basename $0)
echo "You are running $filename"
6
LawrenceLi
this="$(dirname "$(realpath "$BASH_SOURCE")")"

Это разрешает символьные ссылки (это делает realpath), обрабатывает пробелы (это делают двойные кавычки) и находит текущее имя скрипта, даже когда он получен (. ./Myscript) или вызван другими скриптами (это обрабатывает $ BASH_SOURCE). После всего этого хорошо сохранить это в переменной окружения для повторного использования или для простого копирования в другом месте (this =) ...

5
jcalfee314

Вы можете использовать $ 0, чтобы определить имя вашего скрипта (с полным путем) - чтобы получить имя скрипта, вы можете только обрезать эту переменную с помощью

basename $0
5
VolkA

В bash вы можете получить имя файла скрипта, используя $0. Обычно $1, $2 и т.д. Предназначены для доступа к аргументам CLI. Аналогично, $0 предназначен для доступа к имени, которое запускает скрипт (имя файла скрипта).

#!/bin/bash
echo "You are running $0"
...
...

Если вы вызываете скрипт с путем, подобным /path/to/script.sh, тогда $0 также даст имя файла с путем. В этом случае необходимо использовать $(basename $0), чтобы получить только имя файла скрипта.

2
rashok

Информация благодаря Биллу Эрнандесу. Я добавил некоторые предпочтения, которые я принимаю.

#!/bin/bash
function Usage(){
    echo " Usage: show_parameters [ arg1 ][ arg2 ]"
}
[[ ${#2} -eq 0 ]] && Usage || {
    echo
    echo "# arguments called with ---->  ${@}     "
    echo "# \$1 ----------------------->  $1       "
    echo "# \$2 ----------------------->  $2       "
    echo "# path to me --------------->  ${0}     " | sed "s/$USER/\$USER/g"
    echo "# parent path -------------->  ${0%/*}  " | sed "s/$USER/\$USER/g"
    echo "# my name ------------------>  ${0##*/} "
    echo
}

Ура

2
linxuser
echo "$(basename "`test -L ${BASH_SOURCE[0]} \
                   && readlink ${BASH_SOURCE[0]} \
                   || echo ${BASH_SOURCE[0]}`")"
1
ecwpz91

Вот то, что я придумал, вдохновленный Димитр Радулов ответ (который я, кстати, поддержал).

script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"

echo "Called $script with $# argument(s)"

независимо от того, как вы называете свой сценарий

. path/to/script.sh

или же

./path/to/script.sh
0
Salathiel Genèse

echo "Вы бежите $ 0"

0
mmacaulay

$0 не отвечает на вопрос (насколько я понимаю). Демонстрация:

 $ cat script.sh 
 #! /bin/sh
echo `basename $ 0` 
 $ ./script.sh 
 script.sh 
 $ ln script.sh linktoscript 
 $ ./linktoscript 
 linktoscript 

Как получить ./linktoscript, чтобы распечатать script.sh?

[EDIT] Согласно @ephemient в комментариях выше, хотя символическая ссылка может показаться надуманной, можно поиграться с $0 так, чтобы он не представлял ресурс файловой системы. ОП немного двусмысленно о том, что он хотел.

0
Chris Conway
DIRECTORY=$(cd `dirname $0` && pwd)

Я получил вышеупомянутое от другого вопроса переполнения стека, Может ли скрипт Bash сказать, в каком каталоге он хранится?, но я думаю, что это полезно и для этой темы.

0
Koter84