Как определить имя файла сценария Bash внутри самого сценария?
Например, если мой сценарий находится в файле runme.sh, то как мне сделать так, чтобы он отображал сообщение «Вы запускаете runme.sh» без жесткого кодирования?
ИМО, это даст непонятный результат. "Я запустил foo.sh, но он говорит, что я запускаю bar.sh !? Должно быть, это ошибка!" Кроме того, одной из целей использования символических ссылок с разными именами является предоставление различных функциональных возможностей в зависимости от имени, которое оно называется (например, gzip и gunzip на некоторых платформах).
1 То есть, чтобы разрешить символические foo.shссылки таким образом, чтобы при выполнении пользователем, который на самом деле является символической ссылкой bar.sh, вы хотите использовать разрешенное имя, bar.shа не foo.sh.
-1, 1. readlink будет перемещаться только на одну символическую ссылку на глубину, 2. $0в первом примере это разделение слов, 3. $0передается на basename, readlink и echo в позиции, которая позволяет рассматривать его как переключатель командной строки , Я предлагаю вместо этого me=$(basename -- "$0")или намного более эффективно за счет читабельности me=${0##*/}. Для символических ссылок, me=$(basename -- "$(readlink -f -- "$0")")предполагающих использование утилиты gnu, в противном случае это будет очень длинный скрипт, который я не буду здесь писать.
Score_Under
246
# ------------- СЦЕНАРИЙ ------------- # # ------------- ВЫЗОВ ------ ------- ##!/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, то есть имя без какого-либо дополнительного расширения?
Acumenus
Не работает, если скрипт вызывается из другой папки. Путь включен в ${0##*/}. Протестировано с использованием GitBash.
Алик Эльзин-килака
1
Вышеприведенное не работает для меня из скрипта .bash_login, но решение Dimitre Radoulov в $ BASH_SOURCE прекрасно работает.
Джон
@ Джон Конечно, ты имеешь в виду .bash_profile ? Или альтернативно .bashrc ? Вы должны знать, однако, что есть некоторые тонкие различия в том, как они вызваны / получены. Я очень устала, но если я правильно подумаю, проблема, скорее всего, будет. Одно из мест, где это имеет значение, - это если вы входите в систему удаленно, например, через ssh или локальную систему.
Pryftan
193
С 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"
Этот ответ является ИМХО лучшим, потому что решение использует самодокументируемый код. $ BASH_SOURCE полностью понятен без чтения какой-либо документации, тогда как, например, $ {0 ## * /} нет
Andreas M. Oberheim
Этот ответ имеет большую ценность, я верю, потому что, если мы запустим как . <filename> [arguments], $0дадим имя вызывающей оболочки. Ну, по крайней мере, на OSX точно.
Михир
68
Если имя сценария содержит пробелы, более надежный способ заключается в использовании "$0"или "$(basename "$0")"- или на MacOS: "$(basename \"$0\")". Это предотвращает искажение или интерпретацию имени любым способом. Как правило, рекомендуется всегда заключать в кавычки имена переменных в оболочке.
А что, если я хочу это без какого-либо дополнительного расширения файла?
Acumenus
Чтобы удалить расширение, вы можете попробовать «$ {VARIABLE% .ext}», где VARIABLE - это значение, которое вы получили от $ {0 ## * /}, а «.ext» - это расширение, которое вы хотите удалить.
BrianV
19
Чтобы ответить Крису Конвею , в Linux (по крайней мере) вы должны сделать это:
echo $(basename $(readlink -nf $0))
readlink выводит значение символической ссылки. Если это не символическая ссылка, печатается имя файла. -n говорит не печатать перевод строки. -f говорит, что следует полностью перейти по ссылке (если символическая ссылка была ссылкой на другую ссылку, она также разрешит эту ссылку).
-n безвреден, но не обязателен, потому что структура $ (...) его обрежет.
Жаоруфеи
16
Я обнаружил, что эта строка всегда работает, независимо от того, используется ли файл в качестве сценария.
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]}. Встроенная функция вызывающего абонента отображает текущий стек вызовов, используя эту информацию.
Это работает, если вы исходите из файла a (предположим, aчто содержимое echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}") из интерактивного сеанса - тогда он даст вам aпуть. Но если вы пишете сценарий bс source aв нем и работать ./b, он будет возвращать bпуть «s.
PSkocik
12
Эти ответы верны для тех случаев, в которых они указаны, но проблема остается, если вы запускаете сценарий из другого сценария, используя ключевое слово «source» (чтобы он выполнялся в той же оболочке). В этом случае вы получаете $ 0 вызывающего скрипта. И в этом случае я не думаю, что возможно получить название самого сценария.
Это крайний случай, и к нему не следует относиться серьезно. Если вы запустите скрипт из другого скрипта напрямую (без 'source'), будет работать $ 0.
Я согласен, что было бы непонятным разыменовывать символические ссылки, если ваша цель - предоставить обратную связь пользователю, но бывают случаи, когда вам нужно получить каноническое имя для сценария или другого файла, и это лучший способ, imo.
Вы можете использовать $ 0, чтобы определить имя вашего скрипта (с полным путем) - чтобы получить имя скрипта, вы можете только обрезать эту переменную с помощью
Это разрешает символические ссылки (это делает realpath), обрабатывает пробелы (это делают двойные кавычки) и находит текущее имя сценария, даже когда оно получено (. ./Myscript) или вызвано другими сценариями (это обрабатывает $ BASH_SOURCE). После всего этого полезно сохранить это в переменной среды для повторного использования или для простого копирования в другом месте (this =) ...
К вашему сведению, realpathэто не встроенная команда BASH. Это автономный исполняемый файл, который доступен только в определенных дистрибутивах
StvnW
4
В bashвы можете получить имя файла сценария с помощью $0. Как правило $1, и $2т. Д. Для доступа к аргументам CLI. Точно так же $0доступ к имени, которое запускает сценарий (имя файла сценария).
#!/bin/bash
echo "You are running $0"......
Если вы вызываете скрипт с путем, как /path/to/script.shто, то $0также даст имя файла с путем. В этом случае нужно использовать, $(basename $0)чтобы получить только имя файла скрипта.
[EDIT] Согласно @ephemient в комментариях выше, хотя символическая ссылка может показаться надуманной, можно поиграться с тем $0, чтобы она не представляла ресурс файловой системы. ОП немного двусмысленно о том, что он хотел.
добавил ответ на это к моему ответу выше, но я не согласен с тем, что это именно то, что действительно нужно (или что вы должны этого хотеть, за исключением некоторых смягчающих обстоятельств, которые я не могу сейчас понять)
Tanktalus
2
Я думаю, что печать linktoscript вместо script.sh - это особенность, а не ошибка. Несколько команд Unix используют свое имя для изменения своего поведения. Примером является vi / ex / view.
Mouviciel
@Tanktalus: Есть случаи, когда вы хотите, чтобы поведение изменялось в зависимости от реального местоположения файла - в предыдущем проекте у меня был сценарий «Активная ветвь», который вставлял в ссылку несколько путей из той ветки, в которой я находился. работа над; затем эти инструменты могли бы узнать, в какой каталог они были загружены для работы с нужными файлами.
Эндрю Айлетт
2
Информация благодаря Биллу Эрнандесу. Я добавил некоторые предпочтения, которые я принимаю.
#!/bin/bashfunctionUsage(){
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
}
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
fiif[ $ans = n -o $ans = N -o $ans = no -o $ans =No-o $ans = NO ]then
echo "'no'"fireturn $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 Unknownif[-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 rentalcase $val in"trash") start_trash ;;"help") start_help ;;"www") firefox $homepage ;;*) echo "Sorry, I can not get a $val for you!";;esac# Case stop
Ответы:
Для чтения символической ссылки 1 , которая обычно не является тем, что вы хотите (обычно вы не хотите путать пользователя таким образом), попробуйте:
ИМО, это даст непонятный результат. "Я запустил 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, в противном случае это будет очень длинный скрипт, который я не буду здесь писать.источник
show_params
, то есть имя без какого-либо дополнительного расширения?${0##*/}
. Протестировано с использованием GitBash.С bash> = 3 работает следующее:
источник
dirname $BASE_SOURCE
", чтобы получить каталог, в котором находятся скрипты.$BASH_SOURCE
дает правильный ответ при поиске сценария.Это, однако, включает путь, чтобы получить только имя файла сценария, используйте:
источник
. <filename> [arguments]
,$0
дадим имя вызывающей оболочки. Ну, по крайней мере, на OSX точно.Если имя сценария содержит пробелы, более надежный способ заключается в использовании
"$0"
или"$(basename "$0")"
- или на MacOS:"$(basename \"$0\")"
. Это предотвращает искажение или интерпретацию имени любым способом. Как правило, рекомендуется всегда заключать в кавычки имена переменных в оболочке.источник
Если вы хотите это без пути, то вы бы использовали
${0##*/}
источник
Чтобы ответить Крису Конвею , в Linux (по крайней мере) вы должны сделать это:
readlink выводит значение символической ссылки. Если это не символическая ссылка, печатается имя файла. -n говорит не печатать перевод строки. -f говорит, что следует полностью перейти по ссылке (если символическая ссылка была ссылкой на другую ссылку, она также разрешит эту ссылку).
источник
Я обнаружил, что эта строка всегда работает, независимо от того, используется ли файл в качестве сценария.
Если вы хотите следовать символическим ссылкам, используйте их
readlink
по пути, указанному выше, рекурсивно или не рекурсивно.Причина, по которой работает однострочник, объясняется использованием
BASH_SOURCE
переменной среды и ее ассоциированной переменнойFUNCNAME
.[Источник: руководство Bash]
источник
a
(предположим,a
что содержимоеecho "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
) из интерактивного сеанса - тогда он даст вамa
путь. Но если вы пишете сценарийb
сsource a
в нем и работать./b
, он будет возвращатьb
путь «s.Эти ответы верны для тех случаев, в которых они указаны, но проблема остается, если вы запускаете сценарий из другого сценария, используя ключевое слово «source» (чтобы он выполнялся в той же оболочке). В этом случае вы получаете $ 0 вызывающего скрипта. И в этом случае я не думаю, что возможно получить название самого сценария.
Это крайний случай, и к нему не следует относиться серьезно. Если вы запустите скрипт из другого скрипта напрямую (без 'source'), будет работать $ 0.
источник
Поскольку некоторые комментарии спрашивают о имени файла без расширения, вот пример, как это сделать:
Наслаждайтесь!
источник
Re: ответ Tanktalus (принятый) выше, более чистый способ заключается в использовании:
Если ваш скрипт был получен из другого скрипта bash, вы можете использовать:
Я согласен, что было бы непонятным разыменовывать символические ссылки, если ваша цель - предоставить обратную связь пользователю, но бывают случаи, когда вам нужно получить каноническое имя для сценария или другого файла, и это лучший способ, imo.
источник
source
d имена сценариев.Вы можете использовать $ 0, чтобы определить имя вашего скрипта (с полным путем) - чтобы получить имя скрипта, вы можете только обрезать эту переменную с помощью
источник
если ваш вызов сценария оболочки, как
$ 0 - полное имя
Базовое имя $ 0 получит базовое имя файла
и вам нужно поместить это основное имя в переменную, такую как
и добавьте свой дополнительный текст
так что ваши сценарии как
источник
Это разрешает символические ссылки (это делает realpath), обрабатывает пробелы (это делают двойные кавычки) и находит текущее имя сценария, даже когда оно получено (. ./Myscript) или вызвано другими сценариями (это обрабатывает $ BASH_SOURCE). После всего этого полезно сохранить это в переменной среды для повторного использования или для простого копирования в другом месте (this =) ...
источник
realpath
это не встроенная команда BASH. Это автономный исполняемый файл, который доступен только в определенных дистрибутивахВ
bash
вы можете получить имя файла сценария с помощью$0
. Как правило$1
, и$2
т. Д. Для доступа к аргументам CLI. Точно так же$0
доступ к имени, которое запускает сценарий (имя файла сценария).Если вы вызываете скрипт с путем, как
/path/to/script.sh
то, то$0
также даст имя файла с путем. В этом случае нужно использовать,$(basename $0)
чтобы получить только имя файла скрипта.источник
источник
$0
не отвечает на вопрос (насколько я понимаю). Демонстрация:Как можно
./linktoscript
распечататьscript.sh
?[EDIT] Согласно @ephemient в комментариях выше, хотя символическая ссылка может показаться надуманной, можно поиграться с тем
$0
, чтобы она не представляла ресурс файловой системы. ОП немного двусмысленно о том, что он хотел.источник
Информация благодаря Биллу Эрнандесу. Я добавил некоторые предпочтения, которые я принимаю.
ура
источник
Коротко, ясно и просто, в
my_script.sh
Вывод:
источник
Я получил вышеупомянутое от другого вопроса переполнения стека, может ли скрипт Bash сказать, в каком каталоге он хранится? , но я думаю, что это полезно и для этой темы.
источник
Вот что я придумал, вдохновленный Dimitre Radoulov ответ «s (который я upvoted, кстати) .
независимо от того, как вы называете свой сценарий
или
источник
echo "Вы бежите $ 0"
источник
что-то подобное?
источник