Как узнать имя файла скрипта в скрипте Bash?
Как определить имя файла сценария Bash внутри самого сценария?
Например, если мой сценарий находится в файле runme.sh , то как мне сделать так, чтобы он отображал сообщение «Вы запускаете runme.sh» без жесткого кодирования?
Аналогично [Может ли bash-скрипт сказать, в каком каталоге он хранится?] ( To stackoverflow.com/questions/59895/… )
Для чтения символической ссылки 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 .
Это работает, если вас не вызывают по символической ссылке. Но даже тогда, как правило, это то, что вы хотите, IME.
-1, 1. readlink будет перемещаться только на одну символическую ссылку на глубину, 2. $0 в первом примере это разделение слов, 3. $0 передается на basename, readlink и echo в позиции, которая позволяет рассматривать его как переключатель командной строки , Я предлагаю вместо этого me=$(basename — «$0») или намного более эффективно за счет читабельности me=$ . Для символических ссылок, me=$(basename — «$(readlink -f — «$0″)») предполагающих использование утилиты gnu, в противном случае это будет очень длинный скрипт, который я не буду здесь писать.0##*>
# ------------- СЦЕНАРИЙ ------------- # # ------------- ВЫЗОВ ------ ------- # #!/bin/bash echo echo "# arguments called with ----> $ " echo "# \$1 ----------------------> $1 " echo "# \$2 ----------------------> $2 " echo "# path to me ---------------> $ " echo "# parent path --------------> $ " echo "# my name ------------------> $ " 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 # ------------- КОНЕЦ ------------- #
Не работает, если скрипт вызывается из другой папки. Путь включен в $ . Протестировано с использованием GitBash.0##*>
Вышеприведенное не работает для меня из скрипта .bash_login, но решение Dimitre Radoulov в $ BASH_SOURCE прекрасно работает.
@ Джон Конечно, ты имеешь в виду .bash_profile ? Или альтернативно .bashrc ? Вы должны знать, однако, что есть некоторые тонкие различия в том, как они вызваны / получены. Я очень устала, но если я правильно подумаю, проблема, скорее всего, будет. Одно из мест, где это имеет значение, — это если вы входите в систему удаленно, например, через ssh или локальную систему.
С 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 «, чтобы получить каталог, в котором находятся скрипты.
Я почти усвоил эту разницу при написании сценария самоудаления. К счастью, «rm» получил псевдоним «rm -i» 🙂
в любом случае. ./s чтобы получить имя ./s вместо bash? Я обнаружил, что $ 1 не всегда установлен на ./s .
$BASH_SOURCE дает правильный ответ при поиске сценария.
Это, однако, включает путь, чтобы получить только имя файла сценария, используйте:
Этот ответ является ИМХО лучшим, потому что решение использует самодокументируемый код. $ BASH_SOURCE полностью понятен без чтения какой-либо документации, тогда как, например, $ <0 ## */>нет0>
Этот ответ имеет большую ценность, я верю, потому что, если мы запустим как .
Если имя сценария содержит пробелы, более надежный способ заключается в использовании «$0» или «$(basename «$0″)» — или на MacOS: «$(basename \»$0\»)» . Это предотвращает искажение или интерпретацию имени любым способом. Как правило, рекомендуется всегда заключать в кавычки имена переменных в оболочке.
+1 за прямой ответ + лаконично. если нужны функции символической ссылки, я предлагаю посмотреть: ответ Трэвиса Б. Хартвелла.
Если вы хотите это без пути, то вы бы использовали $
Чтобы удалить расширение, вы можете попробовать «$
Чтобы ответить Крису Конвею , в Linux (по крайней мере) вы должны сделать это:
echo $(basename $(readlink -nf $0))
readlink выводит значение символической ссылки. Если это не символическая ссылка, печатается имя файла. -n говорит не печатать перевод строки. -f говорит, что следует полностью перейти по ссылке (если символическая ссылка была ссылкой на другую ссылку, она также разрешит эту ссылку).
Я обнаружил, что эта строка всегда работает, независимо от того, используется ли файл в качестве сценария.
Если вы хотите следовать символическим ссылкам, используйте их readlink по пути, указанному выше, рекурсивно или не рекурсивно.
Причина, по которой работает однострочник, объясняется использованием BASH_SOURCE переменной среды и ее ассоциированной переменной FUNCNAME .
BASH_SOURCE
Переменная массива, членами которой являются имена файлов источника, где определены соответствующие имена функций оболочки в переменной массива FUNCNAME. Функция оболочки $ определена в файле $ и вызвана из $ .
имя_функции
Переменная массива, содержащая имена всех функций оболочки, находящихся в данный момент в стеке вызовов выполнения. Элемент с индексом 0 — это имя любой выполняемой в настоящее время функции оболочки. Самый нижний элемент (с наивысшим индексом) является «основным». Эта переменная существует только при выполнении функции оболочки. Назначения для FUNCNAME не имеют никакого эффекта и возвращают статус ошибки. Если FUNCNAME не установлено, оно теряет свои специальные свойства, даже если оно впоследствии сбрасывается.
Эта переменная может использоваться с BASH_LINENO и BASH_SOURCE. Каждый элемент FUNCNAME имеет соответствующие элементы в BASH_LINENO и BASH_SOURCE для описания стека вызовов. Например, $ был вызван из файла $ по номеру строки $ . Встроенная функция вызывающего абонента отображает текущий стек вызовов, используя эту информацию.
[Источник: руководство Bash]
Это работает, если вы исходите из файла a (предположим, a что содержимое echo «$ — 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.