Tek büyük fark bir kaynak oluşturmak ve yürütmek arasındadır. source foo.shkaynak gösterecek ve gösterdiğiniz diğer tüm örnekler yürütülecektir. Daha ayrıntılı olarak:
./file.sh
Bu file.sh, geçerli dizinde ( ./) adında bir komut dosyası yürütür . Normalde, çalıştırdığınızda command, kabuk $PATHadlı çalıştırılabilir bir dosya için dizinleri arar command. Eğer tam yol verirsek gibi /usr/bin/commandya ./command, o zaman $PATHgöz ardı edilir ve bu belirli dosya yürütülür.
../file.sh
Bu temelde, ./file.shşu anki dizine bakmak yerine file.sh, üst dizine ( ../) bakmak dışındakilerle aynıdır .
sh file.sh
Bu sh ./file.sh, yukarıdaki gibi file.sh, geçerli dizinde çağrılan komut dosyasını çalıştıracaktır . Aradaki fark, onu shkabukla açıkça çalıştırmanızdır . Ubuntu sistemlerinde, öyle dashve değil bash. Genellikle, komut dosyalarının çalıştırılmaları gereken programı veren bir shebang satırı vardır. Onları farklı biriyle çağırmak bunu geçersiz kılar. Örneğin:
$ cat foo.sh
#!/bin/bash
## The above is the shebang line, it points to bash
ps h -p $$ -o args='' | cut -f1 -d' ' ## This will print the name of the shell
Bu komut dosyası, onu çalıştırmak için kullanılan kabuğun adını yazdırır. Farklı şekillerde çağrıldığında ne döndürdüğünü görelim:
$ bash foo.sh
bash
$ sh foo.sh
sh
$ zsh foo.sh
zsh
Bu nedenle, bir komut dosyasını çağırmak çağırmak shell script(mevcutsa) shebang satırını geçersiz kılar ve komut dosyasını söylediğiniz kabukla çalıştırır.
source file.sh veya . file.sh
Buna şaşırtıcı bir şekilde senaryoyu kaynak denir . Anahtar kelime source, kabuk yerleşik .komutunun diğer adıdır . Bu, komut dosyasını geçerli kabukta yürütmenin bir yoludur. Normalde, bir komut dosyası yürütüldüğünde, geçerli kabuktan farklı olan kendi kabuğunda çalıştırılır. Örneklemek gerekirse:
$ cat foo.sh
#!/bin/bash
foo="Script"
echo "Foo (script) is $foo"
Şimdi, değişkeni fooüst kabukta başka bir şeye ayarlarsam ve komut dosyasını çalıştırırsam, komut dosyası farklı bir değer yazdırır foo(çünkü komut dosyasında da ayarlanır), ancak fooüst kabuktaki değeri değişmez:
$ foo="Parent"
$ bash foo.sh
Foo (script) is Script ## This is the value from the script's shell
$ echo "$foo"
Parent ## The value in the parent shell is unchanged
Ancak, komut dosyasını yürütmek yerine kaynak yaparsam foo, üst öğenin değeri değiştirilecek şekilde aynı kabukta çalıştırılır :
$ source ./foo.sh
Foo (script) is Script ## The script's foo
$ echo "$foo"
Script ## Because the script was sourced,
## the value in the parent shell has changed
Bu nedenle, bir betiğin çalıştırdığınız kabuğu etkilemesini istediğiniz birkaç durumda kaynak kullanımı kullanılır. Genellikle kabuk değişkenlerini tanımlamak ve kod bittikten sonra kullanılabilir hale getirmek için kullanılır.
Tüm bunları göz önünde bulundurarak, farklı cevaplar almanızın nedeni, her şeyden önce, komut dosyanızın düşündüğünüzü yapmamasıdır. Çıkışında kaç kez bashgöründüğünü sayar ps. Bu açık terminallerin sayısı değil, çalışan mermilerin sayısıdır (aslında, bu bile değil, ama bu başka bir tartışma). Açıklığa kavuşturmak için betiğinizi biraz basitleştirdim:
#!/bin/bash
logname=terdon
not=`ps -au$logname | grep -c bash`
echo "The number of shells opened by $logname is $not"
Ve sadece tek bir terminal açıkken çeşitli şekillerde çalıştırın:
Doğrudan başlatma ./foo.sh,.
$ ./foo.sh
The number of shells opened by terdon is 1
Burada, mesele hattını kullanıyorsunuz. Bu, komut dosyasının orada ayarlananlar tarafından doğrudan yürütüldüğü anlamına gelir. Bu, betiğin çıktısında gösterilme şeklini etkiler ps. Olarak listelenmek yerine, bash foo.shsadece olarak gösterilir, foo.shbu da greponu özleyeceğiniz anlamına gelir . Aslında çalışan 3 bash örneği vardır: üst işlem, komut dosyasını çalıştıran bash ve pskomutu çalıştıran başka bir örnek . Bu sonuncusu önemlidir, komut değiştirme ( `command`veya $(command)) ile bir komutun başlatılması , üst kabuğun bir kopyasının başlatılmasına ve komutu çalıştırmasına neden olur. Ancak burada, psçıktısını gösterme biçimi nedeniyle bunların hiçbiri gösterilmiyor .
Açık (kabuk) kabukla doğrudan başlatma
$ bash foo.sh
The number of shells opened by terdon is 3
Burada, koştuğunuz bash foo.shiçin çıktısı psgösterilecek bash foo.shve sayılacaktır. Yani, işte, ebeveyn süreç var bashkomut dosyası çalıştıran ve klonlanmış kabuk (çalıştıran ps) artık çünkü tüm gösterilen pskomut kelimesini içerecektir çünkü bunların her gösterecektir bash.
Farklı bir kabukla doğrudan başlatma ( sh)
$ sh foo.sh
The number of shells opened by terdon is 1
Birlikte komut dosyası çalıştıran Bunun nedeni farklıdır shve değil bash. Bu nedenle, tek bashörnek komut dosyanızı başlattığınız üst kabuktur. Yukarıda belirtilen diğer tüm mermiler shbunun yerine çalıştırılıyor .
Kaynak bulma (ya .da source, aynı şeyle)
$ . ./foo.sh
The number of shells opened by terdon is 2
Yukarıda açıkladığım gibi, bir komut dosyasının kaynaklanması, üst işlemle aynı kabukta çalışmasına neden olur. Ancak, pskomutu başlatmak için ayrı bir alt kabuk başlatılır ve bu toplamı ikiye getirir.
Son bir not olarak, çalışan süreçleri saymanın doğru yolu ayrıştırmak psdeğil, kullanmaktır pgrep. Sadece koşsaydın bütün bu problemlerden kaçınılmış olurdu
pgrep -cu terdon bash
Bu nedenle, komut dosyanızın her zaman doğru sayıyı yazdıran çalışan bir sürümü (komut yerine koymanın olmadığını not edin):
#!/usr/bin/env bash
user="terdon"
printf "Open shells:"
pgrep -cu "$user" bash
Bu, kaynak oluşturulduğunda 1 ve diğer tüm başlatma yolları için (çünkü komut dosyasını çalıştırmak için yeni bir bash başlatılacak) döndürecektir. Alt shsüreç olmadığından, başlatıldığında hala 1 dönecektir bash.