Satu-satunya perbedaan utama adalah antara sumber dan pelaksanaan skrip. source foo.shakan sumber itu dan semua contoh lain yang Anda tunjukkan mengeksekusi. Lebih detail:
./file.sh
Ini akan menjalankan skrip bernama file.shyang ada di direktori saat ini ( ./). Biasanya, ketika Anda menjalankan command, shell akan melihat direktori di dalam Anda $PATHuntuk file executable yang disebut command. Jika Anda memberikan path lengkap, seperti /usr/bin/commandatau ./command, maka $PATHdiabaikan dan file tertentu dijalankan.
../file.sh
Ini pada dasarnya sama dengan ./file.shkecuali bahwa alih-alih mencari di direktori saat ini untuk file.sh, itu mencari di direktori induk ( ../).
sh file.sh
Ini setara dengan sh ./file.sh, seperti di atas akan menjalankan skrip yang disebut file.shdalam direktori saat ini. Perbedaannya adalah Anda menjalankannya secara eksplisit dengan shshell. Pada sistem Ubuntu, itu dashdan tidak bash. Biasanya, skrip memiliki garis shebang yang memberikan program yang seharusnya dijalankan. Memanggil mereka dengan yang berbeda akan menimpanya. Sebagai contoh:
$ 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
Script itu hanya akan mencetak nama shell yang digunakan untuk menjalankannya. Mari kita lihat apa yang dikembalikan ketika dipanggil dengan cara yang berbeda:
$ bash foo.sh
bash
$ sh foo.sh
sh
$ zsh foo.sh
zsh
Jadi, panggilan memanggil skrip dengan shell scriptakan menimpa garis shebang (jika ada) dan menjalankan skrip dengan shell apa pun yang Anda katakan.
source file.sh atau . file.sh
Ini disebut, cukup mengejutkan, sumber skrip. Kata kunci sourceadalah alias untuk .perintah builtin shell . Ini adalah cara menjalankan skrip di dalam shell saat ini. Biasanya, ketika sebuah skrip dieksekusi, ia dijalankan di dalam cangkangnya sendiri yang berbeda dari yang sekarang. Menggambarkan:
$ cat foo.sh
#!/bin/bash
foo="Script"
echo "Foo (script) is $foo"
Sekarang, jika saya mengatur variabel fooke sesuatu yang lain di shell induk dan kemudian menjalankan skrip, skrip akan mencetak nilai yang berbeda dari foo(karena itu juga diatur dalam skrip) tetapi nilai foodi dalam shell induk tidak akan berubah:
$ 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
Namun, jika saya sumber skrip alih-alih menjalankannya, skrip akan dijalankan di shell yang sama sehingga nilai foodi dalam induk akan diubah:
$ 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
Jadi, sumber digunakan dalam beberapa kasus di mana Anda ingin skrip memengaruhi shell tempat Anda menjalankannya. Ini biasanya digunakan untuk mendefinisikan variabel shell dan membuatnya tersedia setelah skrip selesai.
Dengan semua itu dalam pikiran, alasan Anda mendapatkan jawaban yang berbeda adalah, pertama-tama, bahwa skrip Anda tidak melakukan apa yang Anda pikirkan. Ini menghitung berapa kali yang bashmuncul di output ps. Ini bukan jumlah terminal terbuka , ini adalah jumlah cangkang yang berjalan (pada kenyataannya, bahkan bukan itu, tapi itu diskusi lain). Untuk memperjelas, saya sedikit menyederhanakan skrip Anda untuk ini:
#!/bin/bash
logname=terdon
not=`ps -au$logname | grep -c bash`
echo "The number of shells opened by $logname is $not"
Dan jalankan dengan berbagai cara hanya dengan satu terminal terbuka:
Peluncuran langsung ./foo.sh,.
$ ./foo.sh
The number of shells opened by terdon is 1
Di sini, Anda menggunakan garis shebang. Ini berarti bahwa skrip dijalankan secara langsung oleh apa pun yang diatur di sana. Ini mempengaruhi cara skrip ditampilkan dalam output dari ps. Alih-alih terdaftar sebagai bash foo.sh, itu hanya akan ditampilkan sebagai foo.shyang berarti bahwa Anda grepakan melewatkannya. Sebenarnya ada 3 instance bash yang berjalan: proses induk, bash menjalankan skrip dan yang lainnya menjalankan psperintah . Yang terakhir ini penting, meluncurkan perintah dengan substitusi perintah ( `command`atau $(command)) menghasilkan salinan shell induk yang diluncurkan dan menjalankan perintah. Di sini, bagaimanapun, tidak ada yang ditampilkan karena cara yang psmenunjukkan hasilnya.
Peluncuran langsung dengan shell eksplisit (bash)
$ bash foo.sh
The number of shells opened by terdon is 3
Di sini, karena Anda menjalankan bash foo.sh, output dari psakan ditampilkan bash foo.shdan dihitung. Jadi, di sini kita memiliki proses induk, bashskrip yang berjalan, dan shell kloning (running the ps) semua ditampilkan karena sekarang psakan menampilkan masing-masing karena perintah Anda akan memasukkan kata bash.
Peluncuran langsung dengan shell yang berbeda ( sh)
$ sh foo.sh
The number of shells opened by terdon is 1
Ini berbeda karena Anda menjalankan skrip dengan shdan tidak bash. Karena itu, satu-satunya bashcontoh adalah shell induk tempat Anda meluncurkan skrip Anda. Semua shell lain yang disebutkan di atas dijalankan oleh shsebagai gantinya.
Sumber (baik dengan .atau source, hal yang sama)
$ . ./foo.sh
The number of shells opened by terdon is 2
Seperti yang saya jelaskan di atas, sumber skrip membuatnya berjalan di shell yang sama dengan proses induk. Namun, subkulit terpisah mulai meluncurkan psperintah dan itu menjadikan total menjadi dua.
Sebagai catatan terakhir, cara yang benar untuk menghitung proses yang sedang berjalan bukan untuk menguraikan pstetapi untuk digunakan pgrep. Semua masalah ini akan dihindari seandainya Anda baru saja berlari
pgrep -cu terdon bash
Jadi, versi skrip Anda yang selalu mencetak angka yang tepat adalah (perhatikan tidak adanya substitusi perintah):
#!/usr/bin/env bash
user="terdon"
printf "Open shells:"
pgrep -cu "$user" bash
Itu akan mengembalikan 1 ketika bersumber dan 2 (karena bash baru akan diluncurkan untuk menjalankan skrip) untuk semua cara lain peluncuran. Itu masih akan mengembalikan 1 ketika diluncurkan dengan shkarena proses anak tidak bash.