Seberapa stabilkah shell Unix “stdin / stdout APIs”?


20

grepping, awking, sedding, dan piping adalah rutinitas sehari-hari dari seorang pengguna sistem operasi mirip Unix, mungkin di baris perintah atau di dalam skrip shell (secara kolektif disebut filter dari sekarang).

Pada intinya, ketika bekerja dengan program CLI Unix "standar" dan shell builtin (secara kolektif disebut perintah mulai sekarang), filter memerlukan format yang diharapkan tepat untuk stdin, stdout, dan stderr di setiap langkah filter agar dapat bekerja dengan benar. Saya menyebut format yang diharapkan dari beberapa perintah ini sebagai API dari perintah ini sebagai berikut.

Sebagai seseorang dengan latar belakang pengembangan web, saya membandingkan jenis pengumpulan data dan pemrosesan data ini secara teknis dengan pengikisan web - suatu teknik yang sangat tidak stabil setiap kali ada sedikit perubahan dalam penyajian data.

Pertanyaan saya sekarang berkaitan dengan stabilitas API perintah Unix.

  1. Apakah perintah dalam sistem operasi mirip Unix mematuhi standardisasi formal sehubungan dengan input dan output mereka?
  2. Pernahkah ada contoh dalam sejarah di mana pembaruan untuk beberapa perintah penting menyebabkan terputusnya fungsi beberapa filter yang dibangun menggunakan versi yang lebih lama dari perintah tersebut?
  3. Apakah perintah Unix telah matang dari waktu ke waktu sehingga benar-benar mustahil untuk mengubah sedemikian rupa sehingga beberapa filter dapat rusak?
  4. Jika filter dapat pecah dari waktu ke waktu karena perubahan API perintah, bagaimana saya sebagai pengembang dapat melindungi filter saya terhadap masalah ini?

Jawaban:


17

Standar POSIX 2008 memiliki bagian yang menjelaskan "Shell dan Utilitas" . Secara umum, jika Anda berpegang teguh pada skrip Anda harus cukup tahan di masa depan, kecuali mungkin untuk penghentian, tetapi skrip tersebut jarang terjadi dalam semalam sehingga Anda harus memiliki banyak waktu untuk memperbarui skrip Anda.

Dalam beberapa kasus di mana format output untuk satu utilitas sangat bervariasi di seluruh platform dan versi, standar POSIX dapat mencakup opsi yang biasanya disebut -patau -Pyang menentukan format output yang dijamin dan dapat diprediksi. Contohnya adalah timeutilitas , yang memiliki implementasi yang sangat beragam. Jika Anda membutuhkan format API / output yang stabil, Anda akan menggunakannya time -p.

Jika Anda perlu menggunakan utilitas filter yang tidak tercakup oleh standar POSIX, maka Anda cukup bergantung pada pengemas distribusi / pengembang hulu, seperti halnya Anda berada di bawah kendali pengembang web jarak jauh ketika melakukan pengikisan web.


12

Saya akan mencoba menjawab dari pengalaman saya.

  1. Perintah tidak benar-benar mematuhi spesifikasi formal, tetapi mereka mematuhi persyaratan untuk mengkonsumsi dan menghasilkan teks yang berorientasi garis.

  2. Ya tentu saja. Sebelum utilitas GNU menjadi standar de facto, banyak vendor akan memiliki output yang unik, terutama sehubungan dengan psdan ls. Ini menyebabkan banyak rasa sakit. Saat ini, hanya HP yang memberikan perintah yang sangat unik. Secara historis, utilitas Berkeley Software Distribution (BSD) adalah terobosan besar dengan masa lalu. Spesifikasi POSIX tidak sesuai dengan masa lalu, tetapi sekarang sudah diterima secara luas.

  3. Perintah Unix memang telah matang dari waktu ke waktu. Masih tidak mustahil untuk memecahkan beberapa skrip yang ditulis untuk versi yang lebih lama. Pikirkan tren terkini menuju UTF-8 sebagai penyandian file teks. Perubahan ini mengharuskan perubahan utilitas dasar seperti tr. Di masa lalu, teks sederhana hampir selalu ASCII (atau sesuatu yang dekat), jadi huruf besar membentuk rentang numerik, seperti halnya huruf kecil. Itu tidak lagi benar dengan UTF-8, jadi trharus menerima opsi baris perintah yang berbeda untuk menentukan hal-hal seperti "huruf besar" atau "alfanumerik".

  4. Salah satu cara terbaik untuk "menyatukan" filter Anda adalah dengan tidak bergantung pada tata letak teks tertentu. Misalnya, jangan lakukan cut -c10-24, yang tergantung pada posisi garis. Gunakan cut -f2sebagai gantinya, yang akan memangkas bidang ke-2 yang dipisahkan tab. awkmemecah setiap jalur input menjadi $ 1, $ 2, $ 3 ... yang merupakan spasi putih yang dipisahkan secara default. Bergantung pada konsep tingkat tinggi seperti "bidang" daripada konsep tingkat rendah seperti posisi kolom. Juga, gunakan ekspresi reguler: seddan awkkeduanya dapat melakukan hal-hal dengan ekspresi reguler yang tidak peduli dengan beberapa variasi input. Trik lain adalah memproses input menjadi sesuatu yang format filter Anda bisa pilih-pilih. Gunakan tr -cs '[a-zA-z0-9]' '[\n]'untuk memecah teks menjadi satu kata per baris, tanpa tanda baca. Kamu tidak


9

Pertama, jawaban yang sangat singkat untuk pertanyaan Anda:

  1. Standarisasi formal dari input / output konvensi: no
  2. Kerusakan di masa lalu karena perubahan keluaran: ya
  3. Sama sekali tidak mungkin untuk mematahkan filter di masa mendatang: tidak
  4. Bagaimana saya bisa melindungi diri terhadap perubahan: bersikap konservatif

Ketika Anda mengatakan "API", Anda menggunakan istilah yang (baik atau buruk) menyiratkan terlalu banyak formalitas di sekitar konvensi input / output filter. Sangat (dan maksud saya "sangat") secara luas, konvensi utama untuk data yang mudah difilter adalah

  • setiap jalur input adalah catatan lengkap
  • dalam setiap catatan, bidang dipisahkan oleh karakter pembatas yang dikenal

Contoh klasik adalah format / etc / passwd. Tetapi, konvensi-konvensi default ini mungkin dilanggar sampai tingkat tertentu lebih sering daripada yang diikuti oleh surat itu.

  • Ada banyak filter (sering ditulis dalam awk atau perl) yang mem-parsing format input multiline.
  • Ada banyak pola input (misalnya, / var / log / messages) di mana tidak ada struktur bidang yang terdefinisi dengan baik, dan teknik berbasis ekspresi reguler yang lebih umum harus digunakan.

Pertanyaan keempat Anda, bagaimana melindungi diri Anda dari variasi dalam struktur output, adalah satu-satunya yang dapat Anda lakukan.

  • Seperti @ jw013 katakan , lihat apa yang dikatakan standar posix. Tentu saja, posix tidak menentukan semua perintah yang ingin Anda gunakan sebagai sumber input.
  • Jika Anda ingin skrip Anda portabel, cobalah untuk menghindari keunikan dari versi apa pun dari beberapa perintah yang kebetulan tidak Anda miliki. Sebagai contoh, banyak versi GNU dari perintah unix standar memiliki ekstensi non-standar. Ini mungkin berguna, tetapi Anda harus menghindarinya jika Anda menginginkan portabilitas maksimum.
  • Cobalah untuk mempelajari apa argumen himpunan bagian perintah dan format output cenderung stabil di seluruh platform. Sayangnya, ini memerlukan akses ke beberapa platform bersamaan dengan waktu, karena perbedaan-perbedaan ini tidak akan ditulis di mana pun, bahkan secara informal.

Pada akhirnya, Anda tidak dapat melindungi diri sepenuhnya dari masalah yang Anda khawatirkan, dan tidak ada satu pun tempat untuk mencari pernyataan "pasti" tentang apa yang harus dilakukan perintah tertentu. Untuk banyak skrip shell, terutama yang ditulis untuk penggunaan pribadi atau skala kecil, ini bukan masalah


5

Hanya mencakup 1) pertanyaan Anda.

Secara alami API selalu dapat berubah atas kehendak pencipta mereka, dan dengan demikian menghancurkan perangkat lunak yang tergantung, dalam bahasa apa pun. Yang mengatakan, ide bagus dari alat Unix ' I / O "API" adalah bahwa praktis tidak ada (mungkin 0x0asebagai akhir baris). Skrip yang baik memfilter data dengan alat Unix alih-alih membuatnya. Itu berarti bahwa skrip Anda dapat rusak karena input atau spek output berubah, tetapi bukan karena format I / O (sekali lagi, sebenarnya tidak ada satu) dari alat individu yang digunakan dalam skrip berubah (karena sesuatu yang tidak benar-benar ada tidak bisa benar - benar berubah).

Akan melalui daftar alat dasar ada beberapa yang saya juga atribut produsen , sebagai lawan hanya filter:

  • wc - mencetak jumlah byte, kata, garis - format yang sangat sederhana, sehingga sama sekali tidak mungkin untuk berubah, dan lebih jauh lagi sangat tidak mungkin untuk digunakan dalam naskah.
  • diff - ada telah berevolusi format output yang berbeda tetapi saya belum pernah mendengar masalah. Juga biasanya tidak digunakan tanpa pengawasan.
  • date - Sekarang di sini kita benar-benar harus memperhatikan apa yang kita hasilkan, terutama mengenai sistem lokal. Tetapi sebaliknya format output adalah RFC'ed mengingat Anda tidak menentukannya sendiri.
  • cal - jangan bicara tentang itu, saya tahu bahwa format output memang sangat berbeda di seluruh sistem.
  • ls , yang , w , lalu - saya tidak bisa membantu jika Anda ingin mengurai ls, hal itu tidak dimaksudkan untuk menjadi. Juga, siapa, yang terakhir adalah pendengar yang lebih interaktif; Jika Anda menggunakannya dalam skrip, Anda harus berhati-hati dengan apa yang Anda lakukan.
  • waktu ditunjukkan di pos lain. Tapi ya, sama dengan ls. Lebih banyak untuk penggunaan interaktif / lokal. Dan bash builtin sangat berbeda dari versi GNU, dan versi GNU telah memiliki bug yang tidak diperbaiki selama bertahun-tahun. Hanya saja, jangan mengandalkan itu.

Berikut adalah alat yang mengharapkan format input tertentu lebih spesifik daripada menjadi aliran byte:

  • bc , dc - kalkulator. Sudah di sisi yang lebih hackish (sungguh, saya tidak menggunakannya dalam skrip), dan mungkin format I / O sangat stabil.

Ada area lain dengan risiko kerusakan yang jauh lebih tinggi, yaitu antarmuka baris perintah. Sebagian besar alat memiliki fitur yang berbeda baik lintas sistem maupun lintas waktu. Contohnya adalah

  • Semua alat yang menggunakan regex - regex dapat mengubah makna berdasarkan sistem lokal (misalnya LC_COLLATE) dan ada banyak seluk-beluk dan kekhususan di seluruh implementasi regex.
  • Cukup tidak menggunakan switch mewah. Anda dapat dengan mudah menggunakan man 1p findmisalnya, untuk membaca manual menemukan POSIX alih-alih halaman manual sistem. Di sistem saya, saya perlu menginstal manpages-posix.

Dan bahkan ketika menggunakan switch seperti itu, biasanya ada kesalahan tidak akan secara halus diperkenalkan dan meracuni data Anda. Sebagian besar program hanya akan menolak untuk bekerja dengan saklar yang tidak dikenal.

Untuk menyimpulkan, saya akan mengatakan bahwa shell sebenarnya berpotensi menjadi salah satu bahasa yang paling portabel (ini portabel ketika Anda skrip portabel). Bandingkan dengan bahasa skrip favorit Anda di mana kesalahan halus terjadi, atau program kompilasi favorit Anda yang akan diserahkan untuk dikompilasi.

Selain itu, di tempat-tempat langka di mana kerusakan dapat terjadi karena ketidakcocokan, mungkin bukan karena waktu yang disebabkan, tetapi karena keragaman di berbagai sistem (artinya jika itu bekerja untuk Anda, itu terjadi 20 tahun sebelum dan akan dalam 20 tahun juga). Itu adalah akibat wajar dari kesederhanaan alat '.


1

Hanya ada standar IO de facto - spasi putih dan output dipisahkan nol.

Mengenai kompatibilitas, kami biasanya kembali memeriksa nomor versi filter individual. Bukan berarti mereka banyak berubah, tetapi ketika Anda ingin menggunakan fitur baru dan masih ingin skrip dijalankan pada versi yang lebih lama, Anda harus "ifdef" keluar entah bagaimana. Praktis tidak ada mekanisme pelaporan kemampuan, kecuali untuk menulis uji kasus secara manual.


0

Naskah memang rusak, beberapa lebih sering daripada yang lain. Perangkat lunak yang lama dan terkenal cenderung tetap relatif sama, dan seringkali memiliki flag kompatibilitas ketika tetap berubah.

Skrip yang ditulis pada satu sistem cenderung terus berfungsi, tetapi sering merusak yang lain.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.