Как определить имя файла сценария 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.
sourced имена сценариев.
если ваш вызов сценария оболочки, как
/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