Çalıştırılmayacak kaynak bir kabuk betiği nasıl tanımlanır


40

Çalıştırmak sourceyerine bir kullanıcının çalışması gereken bir kabuk betiği tanımlıyorum .

Kullanıcıya, örneğin bir dosya uzantısı aracılığıyla durumun böyle olduğunu ima etmenin geleneksel veya akıllı bir yolu var mı?

Dosyanın kendisine yazabileceğim, mesajın yankılanmasına ve kaynak yerine çalıştırıldığında bırakılmasına neden olacak kabuk kodu var mı, böylece kullanıcının bu açık hatayı önlemesine yardımcı olabilirim?


1
Öyleyse, kullanıcı xsadece komutu içeren tek satırlık bir kabuk betiği yazıyorsa . your-script-to-be-sourcedsorun değil, ancak yürütmek bash your-script-to-be-sourcedistiyorsa yasaklanmalı mı? Bu kısıtlamanın amacı nedir?
user1934428

8
@ user1934428 Elbette. Bu, bir dizi envdeğişkeni hesaplayan ve bunları fiili betiğin çıktısı olarak bırakan bir betik için normaldir . Onları çalıştırmalarına izin verirseniz, bir acemi bulmacanın günlerce sıkışıp kalmasına neden olacak.
kubanczyk

Yanıtlar:


45

Bash çalıştırdığınızı varsayarak, aşağıdaki kodu kaynak kodunu almak istediğiniz ancak yürütülmeyen komut dosyasının başlangıcına yakın bir yere koyun:

if [ "${BASH_SOURCE[0]}" -ef "$0" ]
then
    echo "Hey, you should source this script, not execute it!"
    exit 1
fi

Bash altında, ${BASH_SOURCE[0]}kaynaklanıp çalıştırılmadığına bakılmaksızın, kabuğun okuduğu geçerli dosyanın adını içerecektir.

Buna karşılık, $0yürütülmekte olan dosyanın adı.

-efbu iki dosyanın aynı dosya olup olmadığını test eder. Eğer öyleyse, kullanıcıyı uyarır ve çıkarız.

Ne -efde BASH_SOURCEPOSIX vardır. İken -efKsh Yash, zsh ve Dash tarafından desteklenen, BASH_SOURCEBash gerektirir. Inzsh Ancak ${BASH_SOURCE[0]}yerini olabilir ${(%):-%N}.


2
Basitçe echo "Usage: source \"$myfile\""
kubanczyk

6
@kubanczyk sourcetaşınabilir değil. Bu cevabın bas-özgü olduğunu düşününce, o kadar da kötü değil, ancak portatif kullanımı iyi bir alışkanlık.
gronostaj

33

Çalıştırılamayan bir dosya kaynak gösterilebilir ancak yürütülemez, bu nedenle, ilk savunma satırı olarak çalıştırılabilir bayrağın ayarlanmaması iyi bir ipucu olmalı ...

Düzenleme: sadece üzerinde tökezledi hile: Shebang bir kabuk tercüman olmayan herhangi bir çalıştırılabilir olması, /bin/falsekomut dosyası bir hata döndürmesini sağlar (rc! = 0)

#!/bin/false "This script should be sourced in a shell, not executed directly"

7
Ancak, çalıştırılamayan bir dosya hala örneğin bash somefile.sh...
twalberg

1
Eğer bash(vd perl, python, awk ...) ile uygulayabileceğinizi biliyorsanız, daha sonra kaynağa baktınız ve yapmamayacağını yazan yorumu gördünüz :)
xenoid

1
Perl betikleri genellikle somefile.plPython olarak adlandırılır ve somefile.pyöyleyse hayır, muhtemelen yorumları okumamıştım (ne de olsa, hangileri?) Ve bash somefile.shchmod +x somefile.sh; ./somefile.sh
yazmaktan

Ayrıca, bazı Bourne benzeri mermiler de dahil olmak üzere bashilk önce execvebir dosyayı deneyecek , ancak bu başarısız olursa, dosyayı el ile denetler #!ve bu yorumlayıcı aracılığıyla onu el ile yorumlar ve çağırır: bu #!tamamen kullanıcı alanı olan günlerden kalma bir miras Kongre, çekirdeğin kendisi tarafından ele alınmak yerine. Ben düşünüyorum bash , en azından olacak değil olmayan çalıştırılabilir dosyalar için bunu ancak kullanıcı komut dosyası çağırma olabileceğini tüm kabuklarından böyle aklı başında davranışı beklemek taşınabilir olmadığını bilmiyorum.
mtraceur

“Bash ile çalıştırabileceğinizi biliyorsanız,” Um, hayır, bazen kullanıcı sadece diğer kabukları olduğu bash ve bunun bash script.shtehlikeli olabileceği konusunda hiçbir fikri yoktur .
Sergiy Kolodyazhnyy

10

Bu Yığın Taşması yazısında önerilen, Wirawan Purwanto ve mr.spuratic tarafından önerilen fonksiyon temelli olanı sevdiğim birkaç yöntem var :

Wirawan Purwanto tarafından önerildiği gibi en sağlam yöntem, FUNCNAME[1] bir işlev içinde kontrol etmektir :

function mycheck() { declare -p FUNCNAME; }
mycheck

Sonra:

$ bash sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="main")'
$ . sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="source")'

Bu callerdeğerin çıktısını , değerlerini kontrol etmeye mainve sourcearayanın bağlamını ayırt etmeye eşdeğerdir . Kullanmak çıktı FUNCNAME[]yakalamanıza ve ayrıştırmanıza yardımcı olur caller. Doğru olmak için yerel arama derinliğini bilmeniz veya hesaplamanız gerekir. Bir komut dosyasının başka bir işlevden veya komut dosyasının içinden kaynaklandığı durumlar, dizinin (yığının) daha derin olmasına neden olur. ( FUNCNAMEözel bir bash dizi değişkenidir, hiçbir zaman olmadığı sürece çağrı yığınına karşılık gelen bitişik dizinlere sahip olmalıdır unset.)

Böylece betiğin başına ekleyebilirsiniz:

function check()
{
    if [[ ${FUNCNAME[-1]} != "source" ]]   # bash 4.2+, use ${FUNCNAME[@]: -1} for older
    then
        printf "Usage: source %s\n" "$0"
        exit 1
    fi
}
check

7

Senaryoyu çalıştırmanın zararlı değil, sadece yararsız olduğunu varsayarak,

return 0 || printf 'Must be sourced, not executed\n' >&2

için sonuna script. returnişlevin dışında, dosya kaynaklanmadıkça sıfır olmayan bir çıkış kodu bulunur.


3
Bunun 0 çıkış durumu döndürdüğünü unutmayın. Bunun yerine kullandığım benzer deyimi deneyin:return 2>/dev/null; echo "$0: This script must be sourced" 1>&2; exit 1
wjandrea

5

Bir kabuk betiğini kaynakladığınızda, shebang satırı göz ardı edilir. Geçersiz bir shebang koyarak, kullanıcıyı komut dosyasının hatalı şekilde çalıştırıldığı konusunda uyarabilirsiniz:

#!/bin/bash source-this-script
# ...

Hata mesajı şöyle olacaktır:

/bin/bash: source-this-script: No such file or directory

(Rasgele) argüman adı zaten güçlü bir ipucu sağlar, ancak hata mesajı hala% 100 net değildir. Bunu, source-this-scriptsizin yerinize bir yere yerleştirilmiş bir yardımcı program betiği ile çözebiliriz PATH:

#!/bin/sh
echo >&2 "This script must be sourced, not executed${1:+: }${1:-!}"
exit 1

Şimdi, hata mesajı şöyle olacak:

This script must be sourced, not executed: path/to/script.sh

Diğer yaklaşımlarla karşılaştırılması

Diğer cevaplarla karşılaştırıldığında, bu yaklaşım yalnızca her komut dosyasında minimum değişiklikler gerektirir (ve bir shebang satırına sahip olmak, editörlerde dosya türü algılamasına yardımcı olur ve kabuk komut dosyası lehçesini belirtir, bu nedenle faydaları da vardır). Dezavantajı biraz belirsiz bir hata mesajı veya (bir defalık) başka bir kabuk betiğinin eklenmesidir.

bash path/to/script.shOlsa da, açıkça istişareyi engellemez (teşekkürler @muru!).


1
Başka bir dezavantajı, bunun bash some/script.shshebang'ı da görmezden gelecek olana karşı korunmayacağı yönünde.
muru

4
Shebang #!/bin/echo 'You must source this script!'veya benzeri bir şey yaparak mesajı daha net hale getirebilirsiniz .
Chris,

1
@Chris: Doğru, ama sonra dosya türü algılamasını (örneğin Vim'de) ve bunun hangi kabuk lehçesinde bulunduğunu gösteren belgelerini kaybederim. Bunları umursamıyorsanız, öneriniz gerçekten de ikinci senaryodan kurtulur!
Ingo Karkat
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.