Bir kabuk betiğini çalıştırmanın farklı yolları


44

Bir betiği çalıştırmanın birkaç yolu var, bildiğimler:

/path/to/script # using the path (absolute or relative)
. script        # using the . (dot)
source script   # using the `source` command

Bundan daha fazlası var mı? Aralarındaki farklar nelerdir? Birini değil diğerini kullanmam gereken durumlar var mı?


Bilmeniz harika, sorunuzu ve aşağıdaki yanıtları sayesinde, özellikle Shawn'ın. Birkaç test yapana kadar bana görünmeyen bir şey eklemek istiyorum. Bir "/" nin yukarıdaki ikinci şekilde dahil edilmesi, yukarıdaki modu 1 komutuna getirecektir. Yani, "./myscript.sh" mod 1'i takip ederken, ". Myscript.sh" mod 2'ye yapışır. "Yolunu kullanarak (mutlak veya akraba)" demiştiniz, ama sadece bunu açıkça göstermek istediniz.
Arun

Yanıtlar:


32

Başka bir yol, tercümanı çağırmak ve betiğe giden yolu yollamaktır:

/bin/sh /path/to/script

Nokta ve kaynak eşittir. (EDIT: hayır, değiller: KeithB başka bir cevabın yorumunda işaret ettiği gibi, "." Sadece "kaynak" nın hem bash hem de csh ile ilgili kabuklarda çalıştığı bash ile ilgili kabuklarda çalışır.) -place (betiği kopyalayıp yapıştırdığınız gibi). Bu, koddaki tüm işlevler ve yerel olmayan değişkenlerin kalacağı anlamına gelir. Ayrıca, komut dosyası bir dizine bir cd yazarsa, bittiğinde hala orada olacaksınız demektir.

Bir betiği çalıştırmanın diğer yolları onu kendi alt kabuğunda çalıştıracaktır. Koddaki değişkenler, bittiğinde hala hayatta değildir. Komut dosyası dizinleri değiştirdiyse, arama ortamını etkilemez.

/ path / to / script ve / bin / sh scriptleri biraz farklıdır. Genellikle, bir komut dosyasının başında bu gibi görünen bir "shebang" vardır:

#! /bin/bash

Script yorumlayıcısının yolu budur. Çalıştırırken yaptığınızdan farklı bir tercüman belirlerse, farklı davranabilir (veya hiç çalışmayabilir).

Örneğin, Perl komut dosyaları ve Ruby komut dosyaları (sırasıyla) ile başlar:

#! /bin/perl

ve

#! /bin/ruby

Bu komut dosyalarından birini çalıştırarak çalıştırırsanız /bin/sh script, o zaman hiç çalışmazlar.

Ubuntu aslında bash kabuğunu kullanmıyor, ancak çizgi olarak adlandırılana çok benziyor. Bash gerektiren komut dosyaları, çağrılırken biraz yanlış çalışabilir /bin/sh scriptçünkü kısa süre önce tercüman kullanarak bash komut dosyası çağırdınız.

Komut dosyasını doğrudan çağırmakla ve komut dosyası yolunu tercümana iletmek arasındaki bir diğer küçük fark, komut dosyasının doğrudan çalıştırmak için çalıştırılabilir olarak işaretlenmesi gerektiği, ancak yolu tercümana ileterek çalıştırmaması gerektiğidir.

Başka bir küçük varyasyon: eval ile bir komut dosyası yürütmek için bu yollardan herhangi birini ön ekleyebilir, böylece,

eval sh script
eval script
eval . script

ve bunun gibi. Aslında hiçbir şeyi değiştirmez, ama onu eksiksizlik için dahil edeceğimi düşündüm.


6
"Ubuntu aslında bash kabuğunu kullanmıyor" demek kesin ve teknik olarak yanlıştır. Ubuntu yapar Bash kabuğu kullanarak, nokta yani shkarşılık gelir dashama bununla bash.
Faheem Mitha

@Shawn Firts parasında "Senaryoyu yerinde çalıştırır (betiği orada kopyalayıp yapıştırmış gibi) yazmışsınız. Bu, betiğin içindeki herhangi bir fonksiyonun ve yerel olmayan değişkenlerin kalacağı anlamına gelir." Buradaki ikinci satır ile ne demek istiyorsun? Açıklayabilir misin.
Geek

@ Bir komut dosyasını bir alt işlem (normal yol) olarak çalıştırdığınızda, işlem sona erdiğinde tanımladığı tüm değişkenler ve işlevler (onun ortamı) ortadan kalkar. Komut dosyasını kaynakladığınızda, bu değişkenler ve işlevler geçerli ortamda oluşturulur; komut dosyası tamamlandığında, ortamdaki değişiklikler kalır.
Shawn J. Goff,

@ ShawnJ.Goff açıklama için teşekkürler. +1.
Geek

Plot-twist: Bourne Shell (sh) sadece nokta kabul eder - bir bash yapılı olduğu için kaynak değil. pubs.opengroup.org/onlinepubs/9699919799/utilities/… Bu yüzden en taşınabilir yolun nokta olduğunu söyleyebilirim.
dezza

9

Çoğu kişi , komut dosyasına aşağıdaki hata ayıklama bayraklarını ekleyerek kabuk komut dosyalarında hata ayıklar :

set -x     # Print command traces before executing command.
set -v     # Prints shell input lines as they are read.
set -xv    # Or do both

Ancak bu, dosyayı bir düzenleyici ile açmanız (dosyayı düzenleme izniniz olduğunu varsayarak), bir satır ekleyerek set -x, dosyayı kaydederek dosyayı çalıştıracağınız anlamına gelir. Ardından, tamamladığınızda aynı adımları izlemeniz set -x, vb. Gibi işlemleri kaldırmanız gerekir . Bu can sıkıcı olabilir.

Bunları yapmak yerine, komut satırında hata ayıklama bayraklarını ayarlayabilirsiniz:

$ bash -x ~/bin/ducks
+ du -cks -x dir1 dir2 dir3 file1 file2 file3
+ sort -n
+ tail .ducks
123 etc
424 bin
796 total



$ sh -xv ~/bin/ducks  
#!/usr/bin/env bash

# Find the disk hog
# Borrowed from http://oreilly.com/pub/h/15
...
...

2
İlgili bir ipucu: emulate sh 2>/dev/nullShell scriptlerimin en üstüne koyma alışkanlığını kazandım . Zsh ile çalıştırıldığında, bu POSIX uyumlu moda geçer. Diğer mermilerle çalıştırıldığında çizginin etkisi olmaz. Sonra betiği çalıştırabilirim zsh -x /path/to/script. Burada zsh'yi severim çünkü bash veya ksh'dan daha iyi izler sağlar.
Gilles 'SO- kötü olmayı bırak'

7

Shawn J. Goff pek çok iyi noktaya değindi, ancak tüm hikayeyi içermiyor:

Ubuntu aslında bash kabuğunu kullanmıyor, ancak çizgi olarak adlandırılana çok benziyor. Bash gerektiren komut dosyaları, /bin/shkomut dosyası kullanılarak çağrıldığında biraz yanlış çalışabilir çünkü kısa süre önce kısa çizgi yorumlayıcı kullanarak bir bash komut dosyası çağırdınız.

Sistem komut bir çok (init.d içinde, / etc vb gibi) shebang var #!/bin/shama /bin/sheski zamanlarda - Başka kabuğuna bir sembolik bağlantı aslında /bin/bashgünümüzde, /bin/dash. Ancak bunlardan biri olduğu gibi çağrıldığında /bin/sh, farklı davranırlar, yani POSIX-uyumluluk moduna sadık kalırlar.

Bunu nasıl yapıyorlar? Nasıl çağrıldıklarını denetlerler.

Bir shellscript nasıl çalıştırıldığını test edebilir ve buna bağlı olarak farklı şeyler yapabilir mi? Evet yapabilir. Yani onu çağırmanın yolu her zaman farklı sonuçlara yol açabilir, ama elbette seni sinirlendirmek için nadiren yapılır. :)

Temel kural olarak: Eğer bash gibi belirli bir kabuk öğreniyorsanız ve bir bash öğreticisinden komutlar yazıyorsanız , aksi belirtilmediği sürece #!/bin/bashbaşlığa yazmayın #!/bin/sh. Bazı komutlarınız başarısız olabilir. Kendiniz bir komut dosyası yazmadıysanız, bir kabuk ( , ) tahmin etmek yerine doğrudan ( ./foo.sh, bar/foo.sh) öğesini çağırın . Shebang doğru kabuğu çağırmalı.sh foo.shsh bar/foo.sh

Ve işte diğer iki tür istila:

cat foo.sh | dash
dash < foo.sh

5

.ve sourcebir alt işlemi ortaya çıkarmamaları, ancak mevcut kabukta komutları çalıştırmaları bakımından eşdeğerdir. Komut dosyası ortam değişkenleri ayarladığında veya geçerli çalışma dizinini değiştirdiğinde bu önemlidir.

Yolu kullanmak veya onu /bin/shkomutların uygulandığı yeni bir işlem oluşturmak için vermek .


2
sh script
bash script

Daha fazla varsa düşünmek ...

.ve sourceaynı. Uygulamadan sonra herhangi bir çevre değişikliği scripttutulacaktı. Genellikle, bir Bash kütüphanesini kaynaklamak için kullanılır, böylece kütüphanede birçok farklı betikte yeniden kullanılabilir.

Ayrıca mevcut dizini tutmanın iyi bir yolu. Dizini komut dosyasında değiştirirseniz, komut dosyasını yürüttüğünüz kabukta uygulanmayacaktır. Ancak çalıştırması için kaynak yaparsanız, komut dosyası çıktıktan sonra geçerli dizin korunur.


2
.sadece sh / bash ve ilgili mermilerde çalışır. sourceayrıca csh ve ilgili mermilerde de çalışır.
KeithB

1

" Userland exec " farklı bir yol sayıyor mu? Userland exec kodu yükler ve bir execve () sistem çağrısı kullanmadan çalıştırılmasını sağlar.


1
. ./filename
# ( dot space dot slash filename )

Dizin yoldayken komut dosyasını geçerli kabukta çalıştırır.


1

. ve kaynak en azından zsh'de biraz farklı (kullandığım bu) çünkü

source file

İşleri iken

. file

ihtiyacı yok

. ./file
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.