Apakah shell diizinkan untuk mengoptimalkan perintah penghentian yang tidak berguna?

27

Jika sebuah shell diminta untuk melakukan perintah yang mungkin tidak berguna ( atau sebagian tidak berguna ) yang dikenal untuk mengakhiri, seperti cat hugeregularfile.txt > /dev/null, bisakah ia mengabaikan eksekusi perintah itu ( atau menjalankan yang lebih murah, katakanlah, touch -a hugeregularfile.txt )?

Lebih umum, apakah shell mirip dengan kompiler C karena ia dapat melakukan transformasi pada kode sumber, asalkan perilaku yang dapat diamati secara eksternal adalah seolah-olah mesin abstrak mengevaluasinya?

EDIT

Nota Bene: Pertanyaan saya yang semula diajukan memiliki judul yang menanyakan apakah shell diizinkan untuk melakukan optimasi ini, bukan apakah harus atau bahkan apakah implementasi yang dapat melakukannya ada. Saya tertarik pada teori lebih dari praktik, meskipun keduanya diterima.

Iwillnotexist Idonotexist
sumber
Tidak, shell tidak sepintar kompiler modern. Bahkan, ini agak bodoh. Itu tidak akan mengoptimalkan kode yang tidak berguna.
devnull
12
Menebak maksud pengguna bukanlah sesuatu yang harus dilakukan shell. Pengguna bisa mencoba melakukan hampir semua hal dengan perintah itu, mengoptimalkannya akan menjadi hal yang salah untuk dilakukan, bahkan jika itu mungkin.
Chris Down
1
Tidak masalah mengatakan bahwa jika file itu perangkat maka catting itu membuat perbedaan besar. Shell dapat mengetahui bahwa file tersebut adalah perangkat, tetapi tidak perlu dapat diandalkan.
yo
3
@StephaneChazelas C compiler tidak perlu "meminta izin dari seseorang" untuk mengoptimalkan program yang dikompilasi; Ada aturan as-if dalam standar C yang memungkinkan mereka untuk melakukannya. Standar POSIX tampaknya memiliki standar setidaknya satu shell ( pubs.opengroup.org/onlinepubs/009695399/utilities/... ), serta banyak utilitas lainnya ( pubs.opengroup.org/onlinepubs/009604499/utilities/wc.html untuk wc, contohnya). Tapi sepengetahuan saya POSIX tidak mengambil posisi pada optimasi shell; Atau apakah itu?
Iwillnotexist Idonotexist
2
Optimalisasi meningkatkan kinerja dengan pintasan tanpa memengaruhi fungsionalitas. Selama fungsinya dijamin, saya tidak bisa melihat objek POSIX. Meskipun demikian, optimasi yang Anda usulkan akan mematahkan spek kucing . Ada kata-kata khusus dalam spesifikasi POSIX yang ada untuk mengakomodasi jenis optimasi yang dilakukan oleh ksh. Seperti mereka tidak mengatakan proses terpisah tetapi subkulit lingkungan untuk memungkinkan optimasi penghematan garpu.
Stéphane Chazelas

Jawaban:

26

Tidak, itu ide yang buruk.

cat hugeregularfile.txt > /dev/nulldan touch -a hugeregularfile.txttidak sama. catakan membaca seluruh file, bahkan jika Anda mengarahkan output ke /dev/null. Dan membaca seluruh file mungkin persis seperti yang Anda inginkan. Misalnya untuk men-cache-nya sehingga nantinya dibaca akan jauh lebih cepat. Shell tidak bisa mengetahui niat Anda.

Demikian pula, kompiler C tidak akan pernah mengoptimalkan membaca file, bahkan jika Anda tidak melihat hal-hal yang Anda baca.

scai
sumber
2
@Iwillnotexist: Setiap perintah yang berguna (kecuali dapat diperdebatkan truedan false) memiliki potensi efek samping, dan efek sampingnya hampir selalu merupakan titik untuk menjalankan perintah. Shell tidak dapat mengetahui efek samping tersebut di muka (untuk program eksternal seperti cat) tanpa menyelesaikan Masalah Berhenti. Jadi itu benar tidak mencoba, dan menganggap Anda berarti apa yang Anda katakan.
cao
5
@IwillnotexistIdonotexist Tidak, shell tidak dapat melihat semua yang akan terjadi. Ia tidak tahu cat. Bahkan, catbisa melakukan apa saja dari memformat hard drive Anda hingga mengunduh Internet.
scai
5
"Unix tidak dirancang untuk menghentikan penggunanya dari melakukan hal-hal bodoh, karena itu juga akan menghentikan mereka dari melakukan hal-hal yang pintar." - Doug Gwyn
Agi Hammerthief
7
@ cHao Dan genap truedan falseatur $?.
Kyle Strand
3
Seperti @scai tunjukkan di atas, executable tidak seperti kata kunci bahasa: catdan /dev/nullmemiliki arti yang khas tetapi mereka tidak dijamin berperilaku seperti itu. Untuk melakukan optimasi sambil memastikan tidak ada perubahan pada perilaku yang diharapkan, optimasi hanya dapat diizinkan melibatkan konstruksi yang diimplementasikan dalam shell itu sendiri dan bukan hal-hal yang ditemukan di lingkungan eksekusi ... tidak peduli seberapa intuitif nama mereka.
andybuckley
20

Tidak, karena /dev/nullini hanya sebuah nama, yang dapat digunakan untuk perangkat lain atau untuk file selain apa yang "biasanya" merupakan tempat penyimpanan data.

Jadi shell (atau program lain) tidak tahu, berdasarkan namanya, apakah file yang ditulisnya melakukan sesuatu "nyata" dengan data. Ada AFAIK juga tidak ada sistem panggilan program shell dapat membuat, untuk menentukan bahwa misal file descriptor sebenarnya tidak melakukan apa-apa.

Perbandingan Anda dengan mengoptimalkan kode jauh dalam program C tidak berfungsi, karena shell tidak memiliki tinjauan total yang dimiliki oleh kompiler C terhadap sepotong kode sumber. Shell tidak cukup tahu tentang /dev/nullcara mengoptimalkan contoh Anda, lebih seperti kompiler C tidak cukup tahu tentang kode dalam suatu fungsi, sebut saja tautannya secara dinamis, untuk tidak melakukan panggilan.

Anthon
sumber
4
Ternyata, ksh93 akan memperlakukan /dev/nullsecara khusus, kadang-kadang. Sebuah builtin yang memiliki stdout diarahkan ke /dev/null, misalnya echo foo >/dev/null, tidak akan menghasilkan penulisan yang dilakukan /dev/null. Itu tidak melakukan sesuatu yang istimewa jika menjalankan perintah non-builtin (seperti cat file >/dev/null).
Mark Plotnick
Sebenarnya, catbisa juga menjadi hal lain. Sebenarnya ada yang lain.
orion
3
Sebenarnya /dev/nulladalah salah satu dari sangat sedikit jalur standar , bersama dengan /dev/tty, /dev/console, /tmp, /dev/dan /.
Gilles 'SO- berhenti bersikap jahat'
2
@MarkPlotnick Sebenarnya cat adalah ksh93 builtin (tidak diaktifkan kecuali Anda letakkan /opt/ast/binsebelumnya /bin(atau di mana pun cattersedia) $PATH). Dan ya, meskipun cat file > /dev/nulldengan builtin itu readisinya file, itu tidak menulisnya ke / dev / null (meskipun terbuka dan fstats itu).
Stéphane Chazelas
14

Ini tidak akan mengoptimalkan perintah yang sedang berjalan (dan Anda sudah menerima sejumlah jawaban bagus yang mengatakan mengapa tidak), tetapi mungkin mengoptimalkan garpu, pipa / soket, baca dalam beberapa kasus. Jenis optimisasinya:

  • Dengan sebagian besar shell modern, perintah terakhir dalam sebuah skrip umumnya akan dieksekusi dalam proses shell kecuali beberapa traps telah ditetapkan. Misalnya dalam sh -c ls, sebagian besar shimplementasi ( bash, mksh, ksh, zsh, yash, beberapa versi ash) tidak akan garpu proses untuk menjalankan ls.
  • in ksh93, substitusi perintah tidak akan membuat proses pipa atau garpu sampai perintah eksternal dipanggil ( $(echo foo)misalnya akan meluas footanpa pipa / soketpair atau garpu).
  • yang readbuilt-in beberapa kerang ( bash, AT & T ksh) tidak akan melakukan single-byte berbunyi jika mereka mendeteksi stdin adalah seekable (dalam hal ini mereka akan melakukan besar membaca dan mencari kembali ke akhir dari apa yang mereka dimaksudkan untuk membaca).
Stéphane Chazelas
sumber
Saya suka jawaban ini, tetapi tidak jelas apakah ini alasan asli, atau apakah info tersebut diambil dari beberapa referensi (yang ingin saya
selidiki
3
@YoniYalovitsky, itu alasan asli . ksh93adalah shell memimpin di depan optimasi karena tujuannya adalah / harus dilihat setara dengan bahasa pemrograman seperti perl. Jadi Anda dapat melihat kshdokumentasi, kode (semoga sukses) dan milis untuk info lebih lanjut.
Stéphane Chazelas
1
@HenkLangeveld, ya, Anda dapat memverifikasi bahwa dengan sh -c 'ps -p "$$"'yang akan memberi Anda psdan tidak shdengan shimplementasi tersebut, atau dengan strace / truss / tusc ...
Stéphane Chazelas
1
Perbedaan antara ksh -c 'ps; ps'dan bash -c 'ps; ps' menarik. Ksh93 melangkah lebih jauh dalam optimalisasi.
Henk Langeveld
1
@HenkLangeveld, tergantung implementasi apa yang kshsedang kita bicarakan di sini. mkshberperilaku seperti bash. Perilaku itu sebagian besar dimaksudkan untuk mengoptimalkan hal-hal seperti system("some command"). Perhatikan bahwa ada efek samping dari optimasi itu ketika datang ke status keluar dari proses yang diakhiri oleh sinyal (dalam beberapa shell). ksh93dulu memiliki bug karena melakukan optimasi bahkan ketika jebakan ditetapkan.
Stéphane Chazelas
7

Saat melihat cat hugeregularfile.txt > /dev/null, shell tidak boleh percaya bahwa tindakan itu tidak berguna - catbukan bagian dari shell dan bisa melakukan apa pun secara teori, dan juga dalam praktik.

Misalnya, pengguna mungkin telah mengganti nama executable rmmenjadi cat, dan tiba-tiba baris melakukan perilaku yang dapat diamati secara eksternal, yaitu, menghapus file.

Pengguna mungkin telah mengompilasi versi catyang masuk ke loop tak terbatas, sehingga shell tidak dapat berasumsi bahwa itu 'diketahui mengakhiri' seperti yang Anda sarankan.

Seseorang mungkin telah menginstal versi catyang berfungsi sebagaimana dimaksud, tetapi dengan efek samping tambahan menginstal rootkit jika pernah dijalankan dengan hak istimewa yang memadai - sekali lagi, shell harus menjalankannya dengan sepatutnya.

Peter adalah
sumber
2
Sebenarnya, mkshmemang mengoptimalkan V=$(cat file)dengan membuatnya builtin. Jadi shell dapat mengoptimalkannya, tetapi tidak mengubahnya menjadi hanya touch -a.
Steve Schnepp
1
@SteveSchnepp, cat adalah builtin di dalam mksh, tetapi builtin yang masuk ke sistem catjika melewati opsi apa pun, itulah sebabnya dengan GNU cat, mksh -c 'cat /dev/null --help'tidak menghasilkan hasil yang sama seperti bash -c 'cat /dev/null --help', tetapi mksh -c 'cat --help /dev/null'memberikan Anda sama dengan bash -c 'cat --help /dev/null'(seperti mkshcat parsing parses pilihan POSIX cara, sedangkan GNU cat mem-parsing mereka dengan cara GNU).
Stéphane Chazelas
Di bash dan ksh93, V=$(cat file)dapat dioptimalkan dengan V=$(< file). Ini mempercepat bahkan tanpa builtin cat.
Henk Langeveld