perbedaan antara "function foo () {}" dan "foo () {}"

98

Saya dapat mendefinisikan bashfungsi menggunakan atau menghilangkan functionkata kunci. Apakah ada perbedaan?

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

Keduanya panggilan ke fungsi foodan barberhasil dan saya tidak bisa melihat perbedaan. Jadi saya bertanya-tanya apakah itu hanya untuk meningkatkan keterbacaan, atau ada sesuatu yang saya lewatkan ...

BTW di shell lain seperti dash( /bin/shdisinkronkan ke dashdalam debian / ubuntu) gagal ketika menggunakan functionkata kunci.

Carlos Campderrós
sumber
8
Juga dengan atau tanpa kurung: function baz { echo "baz"; }. Lihat Bashism di wiki GreyCat.
manatwork

Jawaban:

43

Tidak ada perbedaan AFAIK, selain fakta bahwa versi kedua lebih portabel.

schaiba
sumber
32
Itu perbedaan BESAR, mudah dibawa ... Saya melihat terlalu banyak jawaban yang tidak berfungsi pada sistem produksi (yang lebih lama), dan juga banyak dengan opsi yang hanya berfungsi di linux. Setidaknya, ingatkan bahwa ini bukan cara yang paling portabel ... Ini bisa sangat berbahaya (meminta seseorang untuk tar cf - /some/thing | ssh user@desthost "cd destinationdir && tar xf - " tidak memperingatkan mereka untuk memeriksa ulang terlebih dahulu apakah versi tar di desthost akan menghilangkan "/" dapat menyebabkan bencana dalam beberapa kasus ...). Misalnya: jika menggunakan function tar { #a safe tar with safety checks ... }dan shmengabaikannya, ...
Olivier Dulac
1
@OlivierDulac Saya akan menambahkan bahwa skrip yang menganggap shmengenali functionkata kunci - dan, secara umum, yang mengasumsikan fitur umum tetapi tidak standar yang disukai kshdan bashditawarkan oleh shell - juga akan sering tidak bekerja pada sistem produksi yang lebih baru , bahkan jika mereka bekerja pada rilis yang lebih lama dari OS yang sama. bashmasih menyediakan shpada banyak sistem GNU / Linux, tetapi beberapa distro populer telah beralih ke shsymlink ke dash(Debian Almquist SHell) untuk meningkatkan kinerja. Ini termasuk Debian dan Ubuntu .
Eliah Kagan
2
Tanpa menguraikan bagaimana sebenarnya itu "lebih portabel", jawabannya tidak berguna.
ivan_pozdeev
Portabilitas bukanlah argumen saat ini di mana industri menggunakan bash atau shell yang setara di> 99,9% dari semua lingkungan. Itu bermuara pada keterbacaan dan ada dua sisi: beberapa orang mengatakan "fungsi" membuatnya jelas, orang yang mempelajarinya dari standar posix atau kerang lain akan mengatakan kawat gigi adalah gaya yang lebih jelas. Pada akhirnya, pilih satu di dalam grup atau perusahaan Anda dan pertahankan.
Hubert Grzeskowiak
95

Kata functionkunci diperkenalkan di ksh . Shell Bourne tradisional hanya memiliki foo ()sintaks, dan POSIX hanya membakukan foo ()sintaks.

Dalam ATT ksh (tetapi bukan pdksh), ada beberapa perbedaan antara fungsi yang didefinisikan oleh functiondan fungsi yang didefinisikan dengan sintaks Bourne / POSIX. Dalam fungsi yang ditentukan oleh function, typesetkata kunci mendeklarasikan variabel lokal: begitu fungsi keluar, nilai variabel diatur ulang ke apa sebelum memasukkan fungsi. Dengan sintaksis klasik, variabel memiliki cakupan global baik Anda gunakan typesetatau tidak.

$ ksh -c 'a=global; f () { typeset a=local; }; f; echo $a'
local
$ ksh -c 'a=global; function f { typeset a=local; }; f; echo $a'
global

Perbedaan lain dalam ksh adalah bahwa fungsi yang didefinisikan dengan functionkata kunci memiliki konteks perangkapnya sendiri. Jebakan yang ditentukan di luar fungsi diabaikan saat menjalankan fungsi, dan kesalahan fatal di dalam fungsi keluar hanya fungsi dan bukan dari keseluruhan skrip. Juga, $0adalah nama fungsi dalam fungsi yang ditentukan oleh functiontetapi nama skrip dalam fungsi yang didefinisikan ().

Pdksh tidak meniru ATT ksh. Dalam pdksh, typesetmembuat variabel cakupan lokal terlepas dari fungsi, dan tidak ada jebakan lokal (meskipun menggunakan functionmemang membuat beberapa perbedaan kecil - lihat halaman manual untuk detail).

Bash dan zsh memperkenalkan functionkata kunci untuk kompatibilitas dengan ksh. Namun dalam shell ini function foo { … }dan foo () { … }sangat identik, seperti ekstensi bash dan zsh function foo () { … }. Kata typesetkunci selalu mendeklarasikan variabel lokal (kecuali dengan -gtentu saja), dan jebakan bukan lokal (Anda bisa mendapatkan jebakan lokal di zsh dengan mengatur local_trapsopsi).

Gilles
sumber
8
Perlu dicatat bahwa dukungan fungsi ditambahkan ke shell Korn sebelum shell Bourne memperkenalkan foo() commandsintaksnya, dan sintaks Bourne kemudian ditambahkan ke shell Korn untuk kompatibilitas.
Stéphane Chazelas
2
Apakah benar function { ... }; f;menghilangkan fsetelah functionkata kunci?
Ruslan
32
foo() any-command

adalah sintaks Bourne yang didukung oleh shell seperti Bourne tetapi bash, yashdan versi terbaru dari posh(yang hanya mendukung perintah majemuk). (Shell Bourne dan implementasi AT&T kshtidak mendukung foo() any-command > redirectionskecuali any-commandperintah majemuk).

foo() any-compound-command

(contoh senyawa perintah: { cmd; }, for i do echo "$i"; done, (cmd)... makhluk yang paling umum digunakan { ...; })

adalah sintaks POSIX yang didukung oleh shell seperti Bourne dan yang umumnya ingin Anda gunakan.

function foo { ...; }

adalah sintaks shell Korn, yang mendahului sintaks Bourne. Hanya gunakan yang ini jika menulis secara spesifik untuk implementasi AT&T dari shell Korn dan perlu perlakuan khusus yang diterimanya di sana. Sintaks itu bukan POSIX, tetapi didukung oleh bash, yashdan zshuntuk kompatibilitas dengan shell Korn meskipun shell tersebut (dan pdkshvarian berbasis shell Korn) tidak memperlakukannya berbeda dari sintaks standar.

function foo () { ...; }

adalah sintaks dari no shell dan tidak boleh digunakan . Itu hanya terjadi harus didukung secara tidak sengaja oleh bash, yash, zshdan pdkshvarian berdasarkan dari shell Korn. Kebetulan, itu juga awksintaks fungsi.

Jika kita terus turun daftar esoteris,

function foo() other-compound-command

(suka function foo() (subshell)atau function foo() for i do; ... done) bahkan lebih buruk. Ini didukung oleh bash, yashdan zsh, tetapi bukan ksh, bahkan pdkshvarian berbasis.

Sementara:

function foo() simple command

hanya didukung oleh zsh.

Stéphane Chazelas
sumber
1
Sintaks yang mencakup functionkata kunci dan tanda kurung didokumentasikan dalam Bash. Manual Bash 4.2 dan yang lebih baru mengatakan bahwa fungsi dideklarasikan oleh sintaks name () compound-command [ redirections ]atau function name [()] compound-command [ redirections ]. Dalam Bash 4.1.11 turun ke setidaknya 3.0-beta yang hanya satu baris [ function ] name () compound-command [redirection]yang keliru tidak mencakup sintaksis yang mencakup functionkata kunci tetapi tidak tanda kurung tetapi masih mencakup sintaksis yang mencakup functionkata kunci dan tanda kurung.
nisetama
@nise, intinya adalah bahwa bashmengenali function foo {selain foo() {untuk kompatibilitas dengan shell Korn (dan selalu memiliki) sehingga dapat menafsirkan skrip yang ditulis untuk shell Korn. Itu memang mendukung function foo () {juga, tetapi tidak ada alasan bagus untuk menggunakannya.
Stéphane Chazelas
2
@ StéphaneChazelas Yah, saya akan mengatakan ada alasan yang baik untuk digunakan function f() {. Yaitu, dalam hal keterbacaan, itu akan diakui sebagai fungsi oleh siapa saja yang tahu bahasa Inggris dan siapa saja yang tahu C, dibandingkan hanya satu dari set ini.
DepressedDaniel
2
Seharusnya jawaban yang diterima. Sangat pentingYou should never combine the keyword function with the parentheses () when defining a function.
4wk_
Selamat datang di 2019, di mana hanya ada satu standar industri de-facto untuk skrip linux / unix automation; satu penerjemah yang dipasang hampir di semua tempat (selain lingkungan eksotis): bash. Tulis kode Anda dengan semua fitur bash, gunakan shebang, dan Anda akan baik-baik saja. Argumen kompatibilitas tidak berlaku.
Hubert Grzeskowiak
22

Secara semantik, kedua bentuk itu setara dalam Bash.

Dari halaman manual:

Fungsi Shell dinyatakan sebagai berikut:

name () compound-command [redirection]
function name [()] compound-command [redirection]

Ini mendefinisikan fungsi bernama name. Fungsi kata yang dipesan adalah opsional. Jika fungsi kata cadangan disediakan, tanda kurung opsional.

EDIT: Saya baru saja memperhatikan bahwa pertanyaan ini ditandai posix. Dalam POSIX sh, functionkata kunci tidak digunakan (meskipun dicadangkan).

depquid
sumber
3

Beberapa orang lain telah menjawab dengan benar sekarang, tetapi inilah sinopsis singkat saya:

Versi kedua adalah portabel dan cenderung bekerja dengan banyak shell standar (terutama POSIX).

Versi pertama hanya akan bekerja dengan bash, tetapi Anda dapat menghilangkan tanda kurung mengikuti nama fungsi dengannya.

Jika tidak, mereka mewakili entitas yang identik setelah bash menginterpretasikannya.

destenson
sumber
sebenarnya, versi pertama tidak masuk akal kecuali untuk membatasi sebagai sintaks yang dapat diterima untuk beberapa shell. bila Anda termasuk () dan yang functionkata kunci shell berperilaku seolah-olah Anda baru saja melakukannya foo(){ ...; }pula, kecuali, tentu saja, untuk shell di mana itu adalah sintaks tidak valid. dan jadi Anda harus melakukannya function foo { ...; }jika Anda harus, atau foo(){ ...; }sebaliknya.
mikeserv