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

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

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

21 ответов


me=`basename ""`

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

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

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


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

#!/bin/bash

echo
echo "# arguments called with ---->  ${@}     "
echo "# $1 ---------------------->         "
echo "# $2 ---------------------->         "
echo "# path to me --------------->       "
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'
#  ---------------------->  'hello there'
#  ---------------------->  '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 ------------- #

С bash > = 3 следующие работы:

$ ./s
0 is: ./s
BASH_SOURCE is: ./s
$ . ./s
0 is: bash
BASH_SOURCE is: ./s

$ cat s
#!/bin/bash

printf ' is: %s\n$BASH_SOURCE is: %s\n' "" "$BASH_SOURCE"

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


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

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

$(basename $BASH_SOURCE) 

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


ответ Крис Конвей, в Linux (по крайней мере) вы бы сделали это:

echo $(basename $(readlink -nf ))

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]}.

FUNCNAME

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

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

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


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

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


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

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

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

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

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


если вызвать скрипт как

/home/mike/runme.sh

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

 /home/mike/runme.sh

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

 runme.sh

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

filename=$(basename )

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

echo "You are running $filename"

так что ваши скрипты как

/home/mike/runme.sh
#!/bin/bash 
filename=$(basename )
echo "You are running $filename"

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

basename 

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

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


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

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

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


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

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

Ура


на bash вы можете получить имя файла сценария, используя . Вообще , etc для доступа к аргументам CLI. Аналогично - это доступ к имени, которое запускает скрипт (имя файла скрипта).

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

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


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

Эхо "вы работаете $0"


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

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

как сделать ./linktoscript распечатать script.sh?

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


DIRECTORY=$(cd `dirname ` && pwd)

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


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

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  ]
then
  val="*** Unknown  ***"
elif [ -n  ]
then
# otherwise make first arg as val
  val=
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