Как определить имя файла сценария Bash внутри самого сценария?
Например, если мой сценарий находится в файле runme.sh
, то как мне сделать так, чтобы он отображал сообщение «Вы запускаете runme.sh» без жесткого кодирования?
Как определить имя файла сценария Bash внутри самого сценария?
Например, если мой сценарий находится в файле runme.sh
, то как мне сделать так, чтобы он отображал сообщение «Вы запускаете runme.sh» без жесткого кодирования?
Ответы:
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
.
$0
в первом примере это разделение слов, 3. $0
передается на basename, readlink и echo в позиции, которая позволяет рассматривать его как переключатель командной строки , Я предлагаю вместо этого me=$(basename -- "$0")
или намного более эффективно за счет читабельности me=${0##*/}
. Для символических ссылок, me=$(basename -- "$(readlink -f -- "$0")")
предполагающих использование утилиты gnu, в противном случае это будет очень длинный скрипт, который я не буду здесь писать.
# ------------- СЦЕНАРИЙ ------------- # # ------------- ВЫЗОВ ------ ------- #
#!/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
# Обратите внимание на следующую строку, первый аргумент вызывается в двойных, # и одинарных кавычках, так как он содержит два слова
$ / misc / shell_scripts / check_root / show_parms . sh "'здравствуй'" "'william'"
# ------------- РЕЗУЛЬТАТЫ ------------- #
# аргументы вызываются с помощью ---> 'hello there' 'william' # $ 1 ----------------------> 'hello there' # $ 2 ---- ------------------> 'william' # путь ко мне --------------> / misc / shell_scripts / check_root / show_parms. sh # родительский путь -------------> / misc / shell_scripts / check_root # мое имя -----------------> show_parms.sh
# ------------- КОНЕЦ ------------- #
show_params
, то есть имя без какого-либо дополнительного расширения?
${0##*/}
. Протестировано с использованием GitBash.
С 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"
dirname $BASE_SOURCE
", чтобы получить каталог, в котором находятся скрипты.
$BASH_SOURCE
дает правильный ответ при поиске сценария.
Это, однако, включает путь, чтобы получить только имя файла сценария, используйте:
$(basename $BASH_SOURCE)
. <filename> [arguments]
, $0
дадим имя вызывающей оболочки. Ну, по крайней мере, на OSX точно.
Если имя сценария содержит пробелы, более надежный способ заключается в использовании "$0"
или "$(basename "$0")"
- или на MacOS: "$(basename \"$0\")"
. Это предотвращает искажение или интерпретацию имени любым способом. Как правило, рекомендуется всегда заключать в кавычки имена переменных в оболочке.
Если вы хотите это без пути, то вы бы использовали ${0##*/}
Чтобы ответить Крису Конвею , в Linux (по крайней мере) вы должны сделать это:
echo $(basename $(readlink -nf $0))
readlink выводит значение символической ссылки. Если это не символическая ссылка, печатается имя файла. -n говорит не печатать перевод строки. -f говорит, что следует полностью перейти по ссылке (если символическая ссылка была ссылкой на другую ссылку, она также разрешит эту ссылку).
Я обнаружил, что эта строка всегда работает, независимо от того, используется ли файл в качестве сценария.
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]
a
(предположим, a
что содержимое echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
) из интерактивного сеанса - тогда он даст вам a
путь. Но если вы пишете сценарий b
с source a
в нем и работать ./b
, он будет возвращать b
путь «s.
Эти ответы верны для тех случаев, в которых они указаны, но проблема остается, если вы запускаете сценарий из другого сценария, используя ключевое слово «source» (чтобы он выполнялся в той же оболочке). В этом случае вы получаете $ 0 вызывающего скрипта. И в этом случае я не думаю, что возможно получить название самого сценария.
Это крайний случай, и к нему не следует относиться серьезно. Если вы запустите скрипт из другого скрипта напрямую (без 'source'), будет работать $ 0.
Поскольку некоторые комментарии спрашивают о имени файла без расширения, вот пример, как это сделать:
FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}
Наслаждайтесь!
Re: ответ Tanktalus (принятый) выше, более чистый способ заключается в использовании:
me=$(readlink --canonicalize --no-newline $0)
Если ваш скрипт был получен из другого скрипта bash, вы можете использовать:
me=$(readlink --canonicalize --no-newline $BASH_SOURCE)
Я согласен, что было бы непонятным разыменовывать символические ссылки, если ваша цель - предоставить обратную связь пользователю, но бывают случаи, когда вам нужно получить каноническое имя для сценария или другого файла, и это лучший способ, imo.
source
d имена сценариев.
если ваш вызов сценария оболочки, как
/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"
this="$(dirname "$(realpath "$BASH_SOURCE")")"
Это разрешает символические ссылки (это делает realpath), обрабатывает пробелы (это делают двойные кавычки) и находит текущее имя сценария, даже когда оно получено (. ./Myscript) или вызвано другими сценариями (это обрабатывает $ BASH_SOURCE). После всего этого полезно сохранить это в переменной среды для повторного использования или для простого копирования в другом месте (this =) ...
realpath
это не встроенная команда BASH. Это автономный исполняемый файл, который доступен только в определенных дистрибутивах
В bash
вы можете получить имя файла сценария с помощью $0
. Как правило $1
, и $2
т. Д. Для доступа к аргументам CLI. Точно так же $0
доступ к имени, которое запускает сценарий (имя файла сценария).
#!/bin/bash
echo "You are running $0"
...
...
Если вы вызываете скрипт с путем, как /path/to/script.sh
то, то $0
также даст имя файла с путем. В этом случае нужно использовать, $(basename $0)
чтобы получить только имя файла скрипта.
$0
не отвечает на вопрос (насколько я понимаю). Демонстрация:
$ cat script.sh #! / Бен / ш echo `basename $ 0` $ ./script.sh script.sh $ ln script.sh linktoscript $ ./linktoscript linktoscript
Как можно ./linktoscript
распечатать script.sh
?
[EDIT] Согласно @ephemient в комментариях выше, хотя символическая ссылка может показаться надуманной, можно поиграться с тем $0
, чтобы она не представляла ресурс файловой системы. ОП немного двусмысленно о том, что он хотел.
Информация благодаря Биллу Эрнандесу. Я добавил некоторые предпочтения, которые я принимаю.
#!/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
}
ура
Коротко, ясно и просто, в my_script.sh
#!/bin/bash
running_file_name=$(basename "$0")
echo "You are running '$running_file_name' file."
Вывод:
./my_script.sh
You are running 'my_script.sh' file.
DIRECTORY=$(cd `dirname $0` && pwd)
Я получил вышеупомянутое от другого вопроса переполнения стека, может ли скрипт Bash сказать, в каком каталоге он хранится? , но я думаю, что это полезно и для этой темы.
Вот что я придумал, вдохновленный Dimitre Radoulov ответ «s (который я upvoted, кстати) .
script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"
echo "Called $script with $# argument(s)"
независимо от того, как вы называете свой сценарий
. path/to/script.sh
или
./path/to/script.sh
что-то подобное?
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