Как узнать имя файла script в Bash script?

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

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

Ответ 1

me='basename "$0"'

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

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

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


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

Ответ 2

# ------------- SCRIPT ------------- #

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

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

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

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

Ответ 3

С 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"

Ответ 4

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

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

$(basename $BASH_SOURCE) 

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

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

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

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

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

BASH_SOURCE

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

имя_функции

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

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

[Источник: Bash manual]

Ответ 9

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

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

Ответ 10

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

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

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

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

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

Ответ 11

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

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

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

Ответ 12

если ваша оболочка script вызывает

/home/mike/runme.sh

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

 /home/mike/runme.sh

basename $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"

Ответ 13

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

basename $0

Ответ 14

this="$(dirname "$(realpath "$BASH_SOURCE")")"

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

Ответ 15

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

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

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

Ответ 16

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

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

Приветствия

Ответ 17

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

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

Как получить ./linktoscript для печати script.sh?

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

Ответ 18

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

Ответ 19

echo "Вы используете $0"

Ответ 21

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

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

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

независимо от способа вызова сценария

. path/to/script.sh

или

./path/to/script.sh

Ответ 22

Коротко, ясно и просто, в my_script.sh

#!/bin/bash

running_file_name=$(basename "$0")

echo "You are running '$running_file_name' file."

Out put:

./my_script.sh
You are running 'my_script.sh' file.

Ответ 23

Что-то вроде этого?

export LC_ALL=en_US.UTF-8
#!/bin/bash
#!/bin/sh

#----------------------------------------------------------------------
start_trash(){
ver="htrash.sh v0.0.4"
$TRASH_DIR  # url to trash $MY_USER
$TRASH_SIZE # Show Trash Folder Size

echo "Would you like to empty Trash  [y/n]?"
read ans
if [ $ans = y -o $ans = Y -o $ans = yes -o $ans = Yes -o $ans = YES ]
then
echo "'yes'"
cd $TRASH_DIR && $EMPTY_TRASH
fi
if [ $ans = n -o $ans = N -o $ans = no -o $ans = No -o $ans = NO ]
then
echo "'no'"
fi
 return $TRUE
} 
#-----------------------------------------------------------------------

start_help(){
echo "HELP COMMANDS-----------------------------"
echo "htest www                 open a homepage "
echo "htest trash               empty trash     "
 return $TRUE
} #end Help
#-----------------------------------------------#

homepage=""

return $TRUE
} #end cpdebtemp

# -Case start
# if no command line arg given
# set val to Unknown
if [ -z $1 ]
then
  val="*** Unknown  ***"
elif [ -n $1 ]
then
# otherwise make first arg as val
  val=$1
fi
# use case statement to make decision for rental
case $val in
   "trash") start_trash ;;
   "help") start_help ;;
   "www") firefox $homepage ;;
   *) echo "Sorry, I can not get a $val   for you!";;
esac
# Case stop