Как определить имя файла Bash script внутри самого script?
Как если бы мой script находился в файле runme.sh
, то как бы я мог заставить его отображать сообщение "Вы используете runme.sh" без hardcoding, что?
me=`basename "$0"`
Для чтения через символическую ссылку, которая обычно не является тем, что вы хотите (вы обычно не хотите путать пользователя таким образом), попробуйте:
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
IMO, что приведет к запутыванию вывода. "Я побежал foo.sh, но он сказал, что я бегу bar.sh!? Должно быть, ошибка!" Кроме того, одна из целей иметь разные имена символических ссылок заключается в предоставлении различных функциональных возможностей, основанных на имени, которое он назвал (думаю, gzip и gunzip на некоторых платформах).
# ------------- 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 ------------- #
${0%/*}
и ${0##*/}
?
С 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
», чтобы получить каталог, в котором находятся сценарии.
Если имя script содержит пробелы в нем, более надежным способом является использование "$0"
или "$(basename "$0")"
- или в MacOS: "$(basename \"$0\")"
. Это препятствует тому, чтобы имя искажалось или интерпретировалось каким-либо образом. В общем, хорошей практикой всегда является двойное цитирование имен переменных в оболочке.
$BASH_SOURCE
дает правильный ответ при поиске script.
Это, однако, включает путь, чтобы получить только имя файла сценариев, используйте:
$(basename $BASH_SOURCE)
Если вы хотите его без пути, вы должны использовать ${0##*/}
Чтобы ответить Крис Конвей, на Linux (по крайней мере) вы сделаете следующее:
echo $(basename $(readlink -nf $0))
readlink выводит значение символической ссылки. Если это не символическая ссылка, она печатает имя файла. -n говорит, что не печатает новую строку. -f сообщает ему, чтобы он полностью следил за ссылкой (если символическая ссылка была ссылкой на другую ссылку, она также решила бы ее).
Эти ответы верны для случаев, о которых они заявляют, но проблема остается, если вы запускаете script из другого script с использованием ключевого слова 'source' (чтобы он работал в той же оболочке). В этом случае вы получаете $0 вызывающего script. И в этом случае я не думаю, что можно получить имя самого script.
Это краевой кейс и его нельзя воспринимать серьезно. Если вы запустите script из другого script напрямую (без "источника" ), использование $0 будет работать.
Я нашел, что эта строка всегда работает, независимо от того, был ли файл получен или запущен как 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]
a
(предположим , что «s содержание является a
echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
) с интерактивной сессии - то это даст вам a
» ы путь , Но если вы напишите скрипт b
с source a
и запустите ./b
, он вернет путь b
.
Re: Tanktalus (принятый) ответ выше, немного более чистый способ использовать:
me=$(readlink --canonicalize --no-newline $0)
Если ваш script был получен из другого bash script, вы можете использовать:
me=$(readlink --canonicalize --no-newline $BASH_SOURCE)
Я согласен с тем, что было бы странно замечать символические ссылки, если ваша цель - предоставить обратную связь пользователю, но бывают случаи, когда вам нужно получить каноническое имя в script или другом файле, и это лучший способ, imo.
source
названия сценариев.
если ваша оболочка 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"
this="$(dirname "$(realpath "$BASH_SOURCE")")"
Это разрешает символические ссылки (realpath делает это), обрабатывает пробелы (двойные кавычки делают это) и найдет текущее имя script даже при использовании источника (./myscript) или вызвано другими скриптами ($ BASH_SOURCE обрабатывает это). В конце концов, полезно сохранить это в переменной среды для повторного использования или для простой копии в другом месте (this =)...
realpath
не является встроенной командой BASH. Это автономный исполняемый файл, который доступен только в определенных дистрибутивах.
Вы можете использовать $0 для определения вашего имени script (с полным путем) - чтобы получить имя script, вы можете обрезать эту переменную с помощью
basename $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
}
Приветствия
echo "$(basename "`test -L ${BASH_SOURCE[0]} \
&& readlink ${BASH_SOURCE[0]} \
|| echo ${BASH_SOURCE[0]}`")"
DIRECTORY=$(cd `dirname $0` && pwd)
Я получил вышеуказанное из другого вопроса о переполнении Stack Может ли Bash script указать, в каком каталоге он хранился?, но я считаю это полезным для эта тема также.
$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
, чтобы он не представлял ресурс файловой системы. ОП немного двусмысленно о том, чего он хотел.
echo "Вы используете $0"
Что-то вроде этого?
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