Як я можу визначити ім'я файлу сценарію Bash всередині самого сценарію?
Як, якщо мій сценарій у файлі runme.sh
, то як би я змусив його відображати повідомлення "Ти працюєш runme.sh" без жорсткого кодування цього?
Як я можу визначити ім'я файлу сценарію Bash всередині самого сценарію?
Як, якщо мій сценарій у файлі runme.sh
, то як би я змусив його відображати повідомлення "Ти працюєш runme.sh" без жорсткого кодування цього?
Відповіді:
me=`basename "$0"`
Для читання через символьне посилання 1 , яке зазвичай не є тим, що ви хочете (зазвичай ви не хочете плутати користувача таким чином), спробуйте:
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
IMO, що дасть заплутаний результат. "Я біг foo.sh, але це говорить про те, що я запускаю bar.sh! Повинна бути помилка!" Крім того, однією з цілей створення по-різному названих символьних посилань є надання різної функціональності на основі імені, яке воно називається (подумайте, gzip та gunzip на деяких платформах).
1 Тобто для вирішення символьних посилань таким чином, що коли користувач виконує, foo.sh
що є насправді символьним посиланням на bar.sh
, ви хочете скористатись розв’язаним ім'ям, bar.sh
а не foo.sh
.
$0
у першому прикладі підлягає розщепленню слова, 3. $0
передається базовому імені, readlink та відлунюється у позиції, що дозволяє розглядати його як комутатор командного рядка . Я пропоную замість me=$(basename -- "$0")
або набагато більш ефективно за рахунок легкості читання me=${0##*/}
. Для символьних посилань, me=$(basename -- "$(readlink -f -- "$0")")
якщо припустити гну утиліти, інакше це буде дуже довгий сценарій, який я тут не напишу.
# ------------- СКРИПТ ------------- # # ------------- ЗВАННІ ------ ------- #
#!/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 ""
# ------------- РЕЗУЛЬТАТИ ------------- #
# аргументи, викликані ---> "привіт, там" "william" # $ 1 ----------------------> "привіт, там" # $ 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##*/}
Щоб відповісти на Chris Conway , в 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]}.
FUNCNAME
Змінна масиву, що містить імена всіх функцій оболонки, що знаходяться в стеці виклику виконання. Елемент з індексом 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
шлях.
Ці відповіді є правильними для випадків, в яких вони констатують, але все ще існує проблема, якщо запустити сценарій з іншого сценарію за допомогою ключового слова "source" (щоб він працював в одній оболонці). У цьому випадку ви отримуєте 0 $ скрипта виклику. І в цьому випадку я не думаю, що можна назвати сам сценарій.
Це кращий випадок, і його не слід сприймати серйозно. Якщо ви запускаєте сценарій з іншого сценарію безпосередньо (без "джерела"), використання $ 0 буде працювати.
Оскільки деякі коментарі запитували про ім’я файлу без розширення, ось приклад, як це зробити:
FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}
Насолоджуйтесь!
Re: Відповідь Танкталуса (прийнято) вище, трохи більш чистим способом є використання:
me=$(readlink --canonicalize --no-newline $0)
Якщо ваш скрипт отримано з іншого сценарію bash, ви можете використовувати:
me=$(readlink --canonicalize --no-newline $BASH_SOURCE)
Я погоджуюсь, що посилання на дереференцію буде заплутаною, якщо вашою метою є надання відгуку користувачеві, але бувають випадки, коли вам потрібно отримати канонічне ім'я до сценарію чи іншого файлу, і це найкращий спосіб, imo.
source
імена сценарію d.
якщо ваш сценарій оболонки виклику, як
/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 робить це), обробляє пробіли (подвійні лапки роблять це) і знайде поточне ім'я сценарію навіть тоді, коли вони розміщені (./myscript) або викликаються іншими сценаріями ($ BASH_SOURCE обробляє це). Зрештою, це добре зберегти в змінній середовища для повторного використання або для простого копіювання в іншому місці (це =) ...
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 `базове ім'я $ 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