Bash betiğindeki komut dosyası dosyasının adını nasıl bilebilirim?


605

Komut dosyasının içindeki Bash komut dosyasının adını nasıl belirleyebilirim?

Eğer runme.shbetiğim dosyadaysa, o zaman bunu kodlamadan "runme.sh çalıştırıyorsunuz" mesajını görüntülemeyi nasıl sağlarım?


3
Benzer [Bir bash betiği hangi dizinde depolandığını söyleyebilir mi?] ( Stackoverflow.com/questions/59895/… için )
Rodrigue

Yanıtlar:


630
me=`basename "$0"`

Genellikle istediğiniz şey olmayan bir symlink 1 ile okumak için (genellikle kullanıcıyı bu şekilde karıştırmak istemezsiniz) deneyin:

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

IMO, kafa karıştırıcı çıktılar üretecek. "Foo.sh'ı çalıştırdım, ama bar.sh çalıştırdığımı söylüyor !? Bir hata olmalı!" Ayrıca, farklı adlandırılmış sembollere sahip olmanın amaçlarından biri, adı verilen isme göre farklı işlevsellik sağlamaktır (bazı platformlarda gzip ve gunzip'i düşünün).


1 Yani, sembolik bağlantıları çözmek için, kullanıcı foo.shaslında bir sembolik bağlantı yürüttüğünde, bunun yerine bar.shçözümlenmiş adı kullanmak istersiniz .bar.shfoo.sh


40
$ 0 size komut dosyasının çağrıldığı adı verir, gerçek komut dosyasının gerçek yolunu değil.
Chris Conway

4
Symlink aracılığıyla çağrılmadığınız sürece çalışır. Ancak, o zaman bile, genellikle ne istersen, IME.
Tanktalus

78
Çağrılanın aksine kaynaklı komut dosyaları için çalışmaz.
Charles Duffy

1
@Charles Duffy: Aşağıdaki Dimitre Radoulov'un cevabına bakınız .
Serge Wautier

8
-1, 1. readlink yalnızca bir symlink derinliğinde seyahat eder, 2. $0ilk örnekte kelime bölmeye tabidir, 3. $0bir komut satırı anahtarı olarak işlem görmesini sağlayan bir konumda basename, readlink ve echo'ya geçirilir . Bunun yerine me=$(basename -- "$0")ya da çok daha verimli bir şekilde okunabilirlik pahasına öneriyorum me=${0##*/}. Simgeler için, me=$(basename -- "$(readlink -f -- "$0")")gnu araçlarını varsayarsak, aksi takdirde burada yazmayacağım çok uzun bir komut dosyası olacaktır.
Score_Under

246
# ------------- SENARYO ------------- # # ------------- ÇAĞRI ------ ------- #

#!/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



# Sonraki satırda dikkat edin, ilk argüman iki kelime içerdiğinden çift, # ve tek tırnak içinde çağrılır


$   / misc / shell_scripts / check_root / show_parms . sh "" merhaba orada "" "" william " 

# ------------- SONUÇLAR ------------- #

# argüman çağrıldı ---> 'merhaba orada' 'william' # $ 1 ----------------------> 'merhaba orada' # 2 $ ---- ------------------> 'william' # bana giden yol --------------> / misc / shell_scripts / check_root / show_parms. sh # üst yol -------------> / misc / shell_scripts / check_root # benim adım -----------------> show_parms.sh






# ------------- SON ------------- #

11
@NickC bkz. Substring Kaldırma
cychoi

1
Nasıl show_params, yani isteğe bağlı uzantısı olmayan adı nasıl alabilirim ?
Acumenus

Komut dosyasının başka bir klasörden çağrılması durumunda çalışmıyor. Yol ${0##*/},. GitBash kullanılarak test edildi.
Ocak

1
Yukarıdakiler benim için bir .bash_login komut dosyasından işe yaramadı, ancak $ BASH_SOURCE $ 'ın Dimitre Radoulov çözümü harika çalışıyor.
John

@John Kesinlikle .bash_profile mı demek istediniz ? Veya alternatif olarak .bashrc ? Yine de, nasıl çağrıldıkları / kaynaklandıkları konusunda bazı ince farklılıklar olduğunu bilmelisiniz. Öldüm yorgunum ama eğer doğru düşünürsem sorun büyük olasılıkla bu olurdu. Önemli olan bir yer, örneğin yerel sistemde ssh ve ssh üzerinden uzaktan sisteme giriş yapmanızdır.
Pryftan

193

İle bash> = 3 aşağıdaki işler:

$ ./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"

24
Harika! Yani hem ./scrip.sh ve kaynak ./script.sh için çalışan cevabı
zhaorufei

4
İstediğim dirname $BASE_SOURCEbudur ve komut dosyalarının bulunduğu dizini almak için " " kullanmak kolaydır .
Larry Cai

2
Kendini silen bir senaryo yazarken bu farkı neredeyse zor bir şekilde öğrendim. Neyse ki 'rm', 'rm -i' olarak adlandırıldı :)
kervin

neyse. ./s adını almak için bash yerine ./s? 1 doların her zaman ./s olarak ayarlanmadığını buldum ...
David Mokon Bond

1
Bu öyle BASH_SOURCE , değil mi?
Dimitre Radoulov

69

$BASH_SOURCE betiği kaynaklarken doğru cevabı verir.

Ancak bu, yalnızca komut dosyalarının dosya adını almak için şu yolu içerir:

$(basename $BASH_SOURCE) 

2
Bu cevap IMHO'nun en iyisidir çünkü çözüm kendi kendini belgeleyen koddan yararlanır. $ BASH_SOURCE herhangi bir belge okumadan tamamen anlaşılabilirken, örneğin $ {0 ## * /} değildir
Andreas M. Oberheim

Biz gibi koşmak çünkü eğer Bu cevap daha fazla değer i inanç olduğunu . <filename> [arguments], $0arayan kabuğun ismini verecekti. En azından OSX'te kesin.
Mihir

68

Komut dosyası adında boşluklar varsa, "$0"veya "$(basename "$0")"- veya MacOS: 'da daha sağlam bir yol kullanmaktır "$(basename \"$0\")". Bu, adın herhangi bir şekilde karıştırılmasını veya yorumlanmasını önler. Genel olarak, her zaman kabuktaki değişken isimlerini çift tırnak içine almak iyi bir uygulamadır.


2
Doğrudan cevap + özlü için +1. Symlink özelliklerine ihtiyacınız varsa görmenizi öneririm: Travis B. Hartwell'in cevabı.
Trevor Boyd Smith

26

Eğer yol olmadan istiyorsanız o zaman ${0##*/}


Ya isteğe bağlı dosya uzantısı olmadan istersem?
Acumenus

Bir uzantıyı kaldırmak için "$ {VARIABLE% .ext}" öğesini deneyebilirsiniz; burada VARIABLE, $ {0 ## * /} 'dan aldığınız değer ve ".ext" kaldırmak istediğiniz uzantıdır.
BrianV

19

Chris Conway'e cevap vermek için Linux'ta (en azından) bunu yaparsınız:

echo $(basename $(readlink -nf $0))

readlink, sembolik bir bağlantının değerini yazdırır. Sembolik bir bağlantı değilse, dosya adını yazdırır. -n bir satırsonu yazdırmamasını söyler. -f bağlantıyı tamamen izlemesini söyler (eğer sembolik bir bağlantı başka bir bağlantının bağlantısıysa, o bağlantıyı da çözer).


2
-n zararsızdır ancak gerekli değildir, çünkü $ (...) yapısı onu keser.
zhaorufei

16

Ben dosya kaynak olup olmadığını veya bir komut dosyası olarak çalıştırmak olsun, her zaman çalışmak için bu satırı buldum.

echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"

Symlinks'i takip etmek istiyorsanız, readlinkyukarıdaki, yinelemeli veya yinelemesiz olarak kullandığınız yolda kullanın .

Tek astarın çalışmasının nedeni, BASH_SOURCEortam değişkeninin ve bunun ilişkilendiricisinin kullanımı ile açıklanmaktadır FUNCNAME.

BASH_SOURCE

Üyeleri FUNCNAME dizi değişkenindeki karşılık gelen kabuk işlev adlarının tanımlandığı kaynak dosya adları olan bir dizi değişkeni. $ {FUNCNAME [$ i]} kabuk işlevi $ {BASH_SOURCE [$ i]} dosyasında tanımlanmış ve $ {BASH_SOURCE [$ i + 1]} dosyasından çağrılmıştır.

FUNCNAME

Yürütme çağrısı yığınında bulunan tüm kabuk işlevlerinin adlarını içeren bir dizi değişkeni. 0 dizinine sahip öğe, şu anda yürütülen herhangi bir kabuk işlevinin adıdır. En alttaki eleman (en yüksek endekse sahip olan eleman) "ana" dır. Bu değişken yalnızca bir kabuk işlevi yürütüldüğünde mevcuttur. FUNCNAME öğesine yapılan atamaların hiçbir etkisi yoktur ve hata durumu döndürür. FUNCNAME ayarlanmamışsa, daha sonra sıfırlansa bile özel özelliklerini kaybeder.

Bu değişken BASH_LINENO ve BASH_SOURCE ile kullanılabilir. FUNCNAME öğesinin her öğesinde, çağrı yığınını açıklamak için BASH_LINENO ve BASH_SOURCE öğelerinde karşılık gelen öğeler bulunur. Örneğin $ {FUNCNAME [$ i]}, $ {BASH_SOURCE [$ i + 1]} dosyasından $ {BASH_LINENO [$ i]} satır numarasından çağrıldı. Arayan yerleşik, bu bilgiyi kullanarak geçerli çağrı yığınını görüntüler.

\. [Kaynak: Bash kılavuzu]


2
Etkileşimli bir oturumdan dosyada kaynak içeriyorsanız (içeriğinin olduğunu a varsayalım ) çalışır - o zaman size yol verir. Eğer bir senaryo yazmak Ama eğer birlikte o ve koşmak , bu dönersiniz 'ın yolunu. aecho "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"absource a./bb
PSkocik

12

Bu yanıtlar belirttikleri durumlar için doğrudur, ancak komut dosyasını 'source' anahtar sözcüğünü kullanarak (aynı kabukta çalışacak şekilde) başka bir komut dosyasından çalıştırırsanız hala bir sorun vardır. Bu durumda, çağıran komut dosyasının $ 0'ını alırsınız. Ve bu durumda, betiğin adını almanın mümkün olduğunu düşünmüyorum.

Bu bir uç durumdur ve çok ciddiye alınmamalıdır. Komut dosyasını başka bir komut dosyasından doğrudan çalıştırırsanız ('kaynak' olmadan), $ 0 kullanmak işe yarayacaktır.


2
Çok iyi bir noktanız var. Kenar durumu IMO değil. Yine de bir çözüm var: Dimitre Radoulov'un yukarıdaki cevabına bakınız
Serge Wautier

10

Bazı yorumlar uzantısız dosya adı hakkında sorduğundan, bunun nasıl yapılacağına dair bir örnek:

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

Zevk almak!


9

Re: Tanktalus'un (kabul edilen) yukarıdaki cevabı, biraz daha temiz bir yol kullanmaktır:

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

Betiğiniz başka bir bash betiğinden alınmışsa aşağıdakileri kullanabilirsiniz:

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

Amacınız kullanıcıya geri bildirimde bulunmak için sembolik bağlantıları kaldırmanın kafa karıştırıcı olacağını kabul ediyorum, ancak kanonik adı bir komut dosyasına veya başka bir dosyaya almanız gerektiğinde durumlar vardır ve bu en iyi yoldur, imo.


1
sourceD komut dosyası adları için teşekkürler .
Fredrick Gauss

8

Komut dosyası adınızı (tam yolla) belirlemek için $ 0 kullanabilirsiniz - komut dosyası adını almak için bu değişkeni yalnızca

basename $0

8

kabuk komut dosyanız gibi

/home/mike/runme.sh

$ 0 tam ad

 /home/mike/runme.sh

basename $ 0 temel dosya adını alacak

 runme.sh

ve bu temel adı aşağıdaki gibi bir değişkene

filename=$(basename $0)

ve ek metninizi ekleyin

echo "You are running $filename"

yani senaryonun

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

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

Bu, sembolik bağlantıları çözer (realpath bunu yapar), boşlukları (çift tırnak işaretleri bunu yapar) ve kaynak ((. ./Myscript) veya diğer komut dosyaları tarafından çağrıldığında ($ BASH_SOURCE bunu işler) bile geçerli komut dosyasının adını bulur. Tüm bunlardan sonra, bunu yeniden kullanmak veya başka bir yerde kolay kopyalamak için bir ortam değişkenine kaydetmek iyidir (this =) ...


3
FYI realpathyerleşik bir BASH komutu değildir. Yalnızca belirli dağıtımlarda kullanılabilen bağımsız bir yürütülebilir
dosyadır

4

İçinde bashkomut dosyası dosyasının adını kullanarak alabilirsiniz $0. Genellikle $1, $2vb erişim CLI bağımsız değişkendir. Benzer şekilde $0, komut dosyasını (komut dosyası adı) tetikleyen ada erişmek için kullanılır.

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

Eğer böyle yol ile komut çağırmak durumunda /path/to/script.sho zaman $0da yol ile dosya adını verecektir. Bu durumda $(basename $0)yalnızca komut dosyası adı almak için kullanmanız gerekir .


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

2

$0soruyu cevaplamıyor (anladığım kadarıyla). Bir gösteri:

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

Kişi nasıl ./linktoscriptçıktı alabilir script.sh?

[EDIT] Yukarıdaki yorumlarda @ephemient başına, sembolik bağlantı olayı anlaşılmış görünse de, $0bir dosya sistemi kaynağını temsil etmeyecek şekilde uğraşmak mümkündür . OP istediği konusunda biraz belirsiz.


Yukarıdaki cevabım için buna cevap ekledim, ama bunun gerçekten istediğini kabul etmedim (ya da bunu istemelisin, şu anda anlayamadığım bazı söndürücü koşulları
yasakladı

2
Ben script.sh yerine linktoscript yazdırmak bir hata değil, bir özellik olduğunu düşünüyorum. Birkaç unix komutu, davranışlarını değiştirmek için adlarını kullanır. Örnek olarak vi / ex / view verilebilir.
mouviciel

@Tanktalus: Davranışın dosyanın gerçek konumuna göre değişmesini istediğiniz durumlar var - önceki bir projede, daldaki çeşitli araçların yoluna simge ekleyecek bir "Etkin dal" komut dosyası vardı üzerinde çalışmak; bu araçlar daha sonra doğru dosyalara karşı çalıştırmak için hangi dizine teslim alındıklarını bulabilir.
Andrew Aylett

2

Bill Hernandez sayesinde bilgi. Kabul ettiğim bazı tercihler ekledim.

#!/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
}

Şerefe


1

Kısa, net ve basit, my_script.sh

#!/bin/bash

running_file_name=$(basename "$0")

echo "You are running '$running_file_name' file."

Çıktı:

./my_script.sh
You are running 'my_script.sh' file.


0

İşte esinlenerek ile geldi budur Dimitre Radoulov 'ın cevabı (Bu arada, upvoted olan) .

script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"

echo "Called $script with $# argument(s)"

senaryonuzu nasıl çağırdığınızdan bağımsız olarak

. path/to/script.sh

veya

./path/to/script.sh


-6

böyle bir şey?

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

5
-1, soruyu cevaplamaz (komut dosyasının adını nasıl bulacağını göstermez) ve çok hatalı bir komut dosyasında kafa karıştırıcı bir örnektir.
Score_Under
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.