Seberapa kompleks suatu program dapat ditulis dalam Bash murni? [Tutup]


17

Setelah beberapa penelitian yang sangat cepat, tampaknya Bash adalah bahasa Turing-lengkap .

Saya bertanya-tanya, mengapa Bash digunakan hampir secara eksklusif untuk menulis skrip yang relatif sederhana? Karena Bash shell hadir dengan Linux, Anda dapat menjalankan skrip shell tanpa interpreter atau kompiler eksternal, seperti yang diperlukan untuk bahasa komputer populer lainnya. Ini adalah keuntungan besar, yang dapat mengimbangi mediokritas bahasa itu sendiri dalam beberapa kasus.

Jadi, apakah ada batasan seberapa rumit program semacam itu bisa didapat? Apakah Bash murni digunakan untuk menulis program yang kompleks? Apakah mungkin untuk menulis, misalnya, file kompresor / decompressor di Bash murni? Kompiler? Gim video sederhana?

Apakah ini jarang digunakan hanya karena hanya ada alat debugging yang sangat terbatas?


2
The shScript configureyang digunakan sebagai bagian dari proses membangun untuk un banyak * x paket tidak 'relatif sederhana'.
user4556274

@ user4556274 Bukan, tapi biasanya juga tidak ditulis dengan tangan tetapi dari set m4makro yang luas .
Kusalananda

2
Ada assembler x86 di Bash, jadi ya, Bash kadang-kadang digunakan untuk menulis program yang kompleks. Mengapa orang tidak melakukan itu lebih sering? Mungkin karena interpreternya juga lambat, jelek, dan rentan terhadap bug "menarik" (lihat fi Shellshock ). Juga, skrip Bash cenderung menjadi lebih sulit secara eksponensial untuk mempertahankan ukurannya. Lihatlah assembler di atas; dapatkah Anda memberi tahu dari sumbernya apakah itu mengikuti AT&T atau sintaks Intel?
Satō Katsura

configureskrip juga lambat, melakukan banyak pekerjaan yang tidak berguna dan telah menjadi subyek beberapa olok-olok lucu. Tentu saja shell dapat digunakan untuk program besar, tetapi sekali lagi orang juga telah membuat komputer dari Game of Life dan Minecraft Conway , dan ada juga bahasa pemrograman seperti Brainf ** k dan Hexagony . Rupanya beberapa orang hanya suka membangun sesuatu dari atom yang sangat kecil dan membingungkan. Anda bahkan dapat menjual game dengan ide itu ...
ilkkachu

Jadi, apakah pertanyaan ini bisa dijawab atau tidak? Mereka menunda dan mengatakan itu tidak bisa dijawab, tetapi saya mendapatkan beberapa jawaban bagus. Akan menyenangkan untuk menjadi koheren, karena saya baru di SE ini, untuk mengarahkan saya ke pertanyaan seperti apa dan tidak diinginkan pada SE ini.
Bregalad

Jawaban:


30

sepertinya Bash adalah bahasa lengkap Turing

Konsep kelengkapan Turing sepenuhnya terpisah dari banyak konsep lain yang berguna dalam bahasa untuk pemrograman dalam skala besar : kegunaan, ekspresif, pemahaman, kecepatan, dll.

Jika Turing-kelengkapan adalah semua yang kami butuhkan, kami tidak akan memiliki bahasa pemrograman sama sekali , bahkan bahasa assembly . Pemrogram komputer semua hanya akan menulis dalam kode mesin , karena CPU kami juga Turing-lengkap.

mengapa Bash digunakan hampir secara eksklusif untuk menulis skrip yang relatif sederhana?

Skrip shell besar dan kompleks - seperti configureskrip yang dihasilkan oleh GNU Autoconf - tidak lazim karena berbagai alasan:

  1. Hingga relatif baru, Anda tidak dapat mengandalkan memiliki shell yang kompatibel dengan POSIX di mana-mana .

    Banyak sistem, terutama yang lebih tua, secara teknis memiliki cangkang kompatibel POSIX di suatu tempat pada sistem, tetapi mungkin tidak berada di lokasi yang dapat diprediksi seperti /bin/sh. Jika Anda menulis skrip shell dan harus dijalankan pada banyak sistem yang berbeda, lalu bagaimana Anda menulis baris shebang ? Salah satu opsi adalah melanjutkan dan menggunakan /bin/sh, tetapi memilih untuk membatasi diri Anda sendiri ke dialek kulit Bourne pra-POSIX jika itu dijalankan pada sistem seperti itu.

    Pra-POSIX Shell Bourne bahkan tidak memiliki aritmatika internal; Anda harus memanggil expratau bcmenyelesaikannya.

    Bahkan dengan shell POSIX, Anda kehilangan array asosiatif dan fitur lain yang kami harapkan akan ditemukan dalam bahasa scripting Unix sejak Perl pertama kali menjadi populer di awal 1990-an .

    Fakta sejarah itu berarti ada tradisi selama puluhan tahun mengabaikan banyak fitur kuat dalam penerjemah skrip shell keluarga Bourne murni karena Anda tidak dapat mengandalkannya di mana-mana.

    Ini masih berlanjut hingga hari ini, pada kenyataannya: Bash tidak mendapatkan array asosiatif sampai versi 4 , tetapi Anda mungkin akan terkejut betapa banyak sistem yang masih digunakan didasarkan pada Bash 3. Apple masih mengirimkan Bash 3 dengan macOS pada 2017 - tampaknya untuk alasan lisensi - dan server Unix / Linux sering menjalankan semua tetapi tidak tersentuh dalam produksi untuk waktu yang sangat lama, sehingga Anda mungkin memiliki sistem lama yang stabil masih menjalankan Bash 3, seperti kotak CentOS 5. Jika Anda memiliki sistem seperti itu di lingkungan Anda, Anda tidak dapat menggunakan array asosiatif dalam skrip shell yang harus dijalankan pada mereka.

    Jika jawaban Anda untuk masalah itu adalah bahwa Anda hanya menulis skrip shell untuk sistem "modern", Anda kemudian harus mengatasi kenyataan bahwa titik referensi umum terakhir untuk sebagian besar shell Unix adalah standar shell POSIX , yang sebagian besar tidak berubah karena itu diperkenalkan pada tahun 1989. Ada banyak cangkang berbeda berdasarkan standar itu, tetapi mereka semua memiliki tingkat yang berbeda dari standar itu. Untuk mengambil array asosiatif lagi, bash, zsh, dan ksh93semua memiliki fitur itu, tapi ada beberapa yang tidak kompatibel implementasi. Pilihan Anda, maka, adalah hanya menggunakan Bash, atau hanya menggunakan Zsh, atau hanya menggunakan ksh93.

    Jika jawaban Anda untuk masalah itu adalah, "jadi instal saja Bash 4," atau ksh93, atau apa pun, lalu mengapa tidak "hanya" menginstal Perl atau Python atau Ruby saja? Itu tidak dapat diterima dalam banyak kasus; masalah bawaan.

  2. Tidak ada modul bahasa scripting shell Bourne keluarga yang mendukung .

    Yang paling dekat dengan sistem modul dalam skrip shell adalah .perintah - alias sourcedalam varian cangkang Bourne yang lebih modern - yang gagal pada beberapa level relatif terhadap sistem modul yang tepat, yang paling mendasar di antaranya adalah namespacing .

    Terlepas dari bahasa pemrograman, pemahaman manusia mulai ditandai ketika setiap file dalam program keseluruhan yang lebih besar melebihi beberapa ribu baris. Alasan utama kami menyusun program besar menjadi banyak file adalah agar kami dapat mengabstraksikan kontennya menjadi satu atau dua kalimat paling banyak. File A adalah pengurai baris perintah, file B adalah jaringan I / O pump, file C adalah shim antara library Z dan program lainnya, dll. Ketika satu-satunya metode Anda untuk merakit banyak file ke dalam satu program adalah inklusi teks , Anda membatasi seberapa besar program Anda dapat tumbuh secara wajar.

    Sebagai perbandingan, akan seperti jika bahasa pemrograman C tidak memiliki linker, hanya #includepernyataan. Dialek C-lite seperti itu tidak membutuhkan kata kunci seperti externatau static. Fitur-fitur itu ada untuk memungkinkan modularitas.

  3. POSIX tidak mendefinisikan cara untuk lingkup variabel ke fungsi skrip shell tunggal, apalagi ke file.

    Ini secara efektif membuat semua variabel global , yang lagi-lagi merusak modularitas dan kompabilitas.

    Ada solusi untuk ini dalam shell post-POSIX - tentu saja bash, ksh93dan zshsetidaknya - tetapi itu hanya membawa Anda kembali ke poin 1 di atas.

    Anda dapat melihat efek dari ini dalam panduan gaya pada penulisan makro GNU Autoconf, di mana mereka merekomendasikan Anda mengawali nama variabel dengan nama makro itu sendiri, yang mengarah ke nama variabel yang sangat panjang murni untuk mengurangi kemungkinan tabrakan untuk diterima dekat nol.

    Bahkan C lebih baik dalam skor ini, satu mil. Tidak hanya sebagian besar program C ditulis terutama dengan variabel fungsi-lokal, C juga mendukung pelingkupan blok, yang memungkinkan beberapa blok dalam fungsi tunggal untuk menggunakan kembali nama variabel tanpa kontaminasi silang.

  4. Bahasa pemrograman Shell tidak memiliki perpustakaan standar.

    Dimungkinkan untuk berpendapat bahwa pustaka standar bahasa scripting shell adalah isinya PATH, tetapi itu hanya mengatakan bahwa untuk menyelesaikan segala sesuatu yang konsekuensinya, skrip shell harus memanggil seluruh program lain, mungkin yang ditulis dalam bahasa yang lebih kuat untuk mulai dengan.

    Juga tidak ada arsip pustaka utilitas shell yang banyak digunakan seperti Perl CPAN . Tanpa perpustakaan besar yang tersedia kode utilitas pihak ketiga, seorang programmer harus menulis lebih banyak kode dengan tangan, jadi dia kurang produktif.

    Bahkan mengabaikan fakta bahwa sebagian besar skrip shell bergantung pada program eksternal yang biasanya ditulis dalam C untuk menyelesaikan sesuatu yang berguna, ada overhead dari semua pipe()fork()exec()rantai panggilan tersebut. Pola itu cukup efisien di Unix, dibandingkan dengan IPC dan proses peluncuran pada OS lain, tetapi di sini secara efektif menggantikan apa yang akan Anda lakukan dengan panggilan subrutin dalam bahasa scripting lain, yang masih jauh lebih efisien. Itu menempatkan batas yang serius pada batas atas kecepatan eksekusi skrip shell.

  5. Skrip Shell memiliki sedikit kemampuan bawaan untuk meningkatkan kinerjanya melalui eksekusi paralel.

    Shell Bourne punya &, waitdan pipeline untuk ini, tapi itu sebagian besar hanya berguna untuk menyusun beberapa program, bukan untuk mencapai paralelisme CPU atau I / O. Anda tidak mungkin dapat mematok inti atau menjenuhkan array RAID hanya dengan skrip shell, dan jika Anda melakukannya, Anda mungkin bisa mencapai kinerja yang jauh lebih tinggi dalam bahasa lain.

    Jaringan pipa khususnya adalah cara yang lemah untuk meningkatkan kinerja melalui eksekusi paralel. Itu hanya memungkinkan dua program berjalan secara paralel, dan salah satu dari dua kemungkinan akan diblokir pada I / O ke atau dari yang lain pada suatu titik waktu tertentu.

    Ada cara-cara jaman akhir di sekitar ini, seperti xargs -Pdan GNUparallel , tetapi ini hanya beralih ke poin 4 di atas.

    Dengan tidak adanya kemampuan bawaan untuk mengambil keuntungan penuh dari sistem multi-prosesor, skrip shell akan selalu lebih lambat daripada program yang ditulis dengan baik dalam bahasa yang dapat menggunakan semua prosesor dalam sistem. Untuk mengambil configurecontoh skrip Autoconf GNU itu lagi, menggandakan jumlah inti dalam sistem tidak akan banyak membantu meningkatkan kecepatannya.

  6. Bahasa skrip shell tidak memiliki pointer atau referensi .

    Ini mencegah Anda dari melakukan banyak hal dengan mudah dilakukan dalam bahasa pemrograman lain.

    Untuk satu hal, ketidakmampuan untuk merujuk secara tidak langsung ke struktur data lain dalam memori program berarti Anda terbatas pada struktur data bawaan . Shell Anda mungkin memiliki array asosiatif , tetapi bagaimana penerapannya? Ada beberapa kemungkinan, masing-masing dengan pengorbanan yang berbeda: pohon merah-hitam , pohon AVL , dan tabel hash adalah yang paling umum, tetapi ada yang lain. Jika Anda memerlukan serangkaian pengorbanan yang berbeda, Anda buntu, karena tanpa referensi, Anda tidak memiliki cara untuk memutarbalikkan banyak jenis struktur data tingkat lanjut. Anda terjebak dengan apa yang diberikan kepada Anda.

    Atau, mungkin Anda membutuhkan struktur data yang bahkan tidak memiliki alternatif yang memadai yang dibangun ke dalam juru bahasa skrip shell Anda, seperti grafik asiklik terarah , yang mungkin Anda perlukan untuk memodelkan grafik dependensi . Saya telah memprogram selama beberapa dekade, dan satu-satunya cara saya bisa memikirkan untuk melakukan itu dalam skrip shell adalah dengan menyalahgunakan sistem file , menggunakan symlinks sebagai referensi palsu. Itulah jenis solusi yang Anda dapatkan ketika Anda hanya mengandalkan kelengkapan Turing, yang tidak memberi tahu Anda apakah solusi itu elegan, cepat, atau mudah dimengerti.

    Struktur data lanjutan hanyalah satu penggunaan untuk pointer dan referensi. Ada tumpukan aplikasi lain untuk mereka , yang tidak bisa dilakukan dengan mudah dalam bahasa skrip shell keluarga Bourne.

Saya bisa terus dan terus, tetapi saya pikir Anda mengerti maksudnya di sini. Sederhananya, ada banyak bahasa pemrograman yang lebih kuat untuk sistem tipe Unix.

Ini adalah keuntungan besar, yang dapat mengimbangi mediokritas bahasa itu sendiri dalam beberapa kasus.

Tentu, dan itulah mengapa GNU Autoconf menggunakan subset sengaja dari keluarga Bourne bahasa skrip shell untuk configureoutput skripnya: sehingga configureskripnya akan berjalan cukup banyak di mana-mana.

Anda mungkin tidak akan menemukan kelompok orang percaya yang lebih besar dalam kegunaan menulis dalam dialek kulit Bourne yang sangat portabel daripada pengembang GNU Autoconf, namun kreasi mereka sendiri ditulis terutama dalam Perl, ditambah beberapa m4, dan hanya sedikit shell naskah; hanya keluaran Autoconf yang merupakan skrip shell Bourne murni. Jika itu tidak menimbulkan pertanyaan tentang seberapa berguna konsep "Bourne everywhere", saya tidak tahu apa yang akan terjadi.

Jadi, apakah ada batasan seberapa rumit program semacam itu bisa didapat?

Secara teknis, tidak, seperti yang disarankan pengamatan kelengkapan Turing Anda.

Tapi itu tidak sama dengan mengatakan bahwa skrip shell yang besar dan sewenang-wenang itu menyenangkan untuk ditulis, mudah di-debug, atau dieksekusi dengan cepat.

Apakah mungkin untuk menulis, katakanlah, file kompresor / decompressor di bash murni?

"Murni" Bash, tanpa ada panggilan untuk hal-hal di PATH? Kompresor mungkin dapat dilakukan dengan menggunakan echodan melepaskan urutan hex, tetapi akan cukup menyakitkan untuk dilakukan. Dekompresor mungkin tidak dapat ditulis seperti itu karena ketidakmampuan untuk menangani data biner dalam shell . Anda akhirnya memanggil oddan menerjemahkan data biner ke format teks, cara asli shell dalam menangani data.

Setelah Anda mulai berbicara tentang menggunakan shell scripting seperti yang dimaksudkan, seperti lem untuk mendorong program lain di PATH, pintu terbuka, karena sekarang Anda hanya terbatas pada apa yang dapat dilakukan dalam bahasa pemrograman lain, yang berarti Anda tidak memiliki batasan sama sekali. Sebuah shell script yang mendapat semua kekuatannya dengan menelepon ke program lain di PATHtidak berlari secepat program monolitik yang ditulis dalam bahasa yang lebih kuat, tetapi tidak berjalan.

Dan itu intinya. Jika Anda membutuhkan program untuk menjalankan cepat, atau jika perlu kuat sendiri daripada meminjam kekuatan dari orang lain, Anda tidak menulisnya dalam shell.

Gim video sederhana?

Berikut Tetris di shell . Game seperti lainnya tersedia, jika Anda mencari.

hanya ada alat debugging yang sangat terbatas

Saya akan menempatkan dukungan alat debugging turun sekitar 20 tempat pada daftar fitur yang diperlukan untuk mendukung pemrograman dalam ukuran besar. Banyak programmer yang lebih mengandalkan printf()debugging daripada debugger yang tepat, terlepas dari bahasa.

Dalam shell, Anda memiliki echodan set -x, yang bersama-sama cukup untuk men-debug banyak masalah besar.


2
"Script Shell memiliki sedikit kemampuan bawaan untuk melakukan eksekusi paralel." Menurut pendapat saya shell memiliki dukungan yang lebih baik untuk pemrosesan paralel daripada kebanyakan bahasa lainnya. Dengan satu karakter &Anda dapat menjalankan proses secara paralel. Anda dapat waitmenyelesaikan proses anak. Anda dapat mengatur jaringan pipa, dan jaringan pipa yang lebih kompleks menggunakan pipa bernama. Yang paling penting, mudah untuk melakukan pemrosesan paralel dengan cara yang benar, dengan kode boilerplate yang sangat sedikit dan menghindari risiko dan kesulitan multi-threading shared-memory.
Sam Watkins

@ SamWatkins: Saya telah memperbarui poin 5 di atas untuk menjawab balasan Anda. Sementara saya, juga penggemar penyampaian pesan antara proses terpisah sebagai cara untuk menghindari banyak masalah yang melekat dalam paralelisme memori bersama, poin yang saya sampaikan di sini adalah tentang peningkatan kinerja, bukan tentang komposabilitas dan semacamnya, dan bahwa sering membutuhkan paralelisme memori bersama.
Warren Young

Script Shell baik untuk prototyping - tetapi pada akhirnya suatu proyek harus pindah ke bahasa pemrograman yang tepat, maka idealnya bahasa dikompilasi. Kemudian dalam kasus ekstrem perakitan, seperti yang Anda lihat dengan proyek FFmpeg. Cmake adalah contoh yang baik tentang apa yang harus terjadi pada Autotools - yang ditulis dalam C dan tidak memerlukan Perl atau Texinfo atau M4. Semacam memalukan benar-benar bahwa Autotools masih sangat bergantung pada skrip shell setelah 30 tahun wikipedia.org/wiki/GNU_Build_System#Criticism
Steven Penny

9

Kita bisa berjalan atau berenang di mana saja, jadi mengapa kita repot dengan sepeda, mobil, kereta api, kapal, pesawat terbang dan kendaraan lain? Tentu, berjalan atau berenang bisa melelahkan, tetapi ada keuntungan besar karena tidak membutuhkan peralatan tambahan.

Untuk satu hal, meskipun bash adalah Turing-complete, itu tidak pandai memanipulasi data selain bilangan bulat (tidak terlalu besar), string, (satu dimensi) array string, dan peta yang terbatas dari string ke string. Jenis data lain membutuhkan pengkodean yang merepotkan, yang membuatnya sulit untuk menulis program dan sering kali memaksakan kinerja yang tidak cukup baik dalam praktiknya. Misalnya, operasi floating-point di bash sulit dan lambat.

Selain itu, bash memiliki sedikit cara berinteraksi dengan lingkungannya. Ini dapat menjalankan proses, dapat melakukan beberapa jenis akses file sederhana (melalui pengalihan), dan hanya itu. Bash juga memiliki klien jaringan sisi klien. Bash dapat memancarkan null byte dengan cukup mudah ( printf \\0) tetapi tidak mem-parsing null byte dalam inputnya, yang membuatnya tidak cocok untuk membaca data biner. Bash tidak dapat langsung melakukan hal-hal lain: ia harus memanggil program eksternal untuk itu. Dan itu tidak masalah: cangkang dirancang untuk tujuan utama menjalankan program eksternal! Kerang adalah bahasa lem untuk menggabungkan program bersama. Tetapi jika Anda menjalankan program eksternal, itu berarti program itu harus tersedia - dan kemudian Anda mengurangi keuntungan portabilitas:).

Bash tidak memiliki fitur apa pun yang membuatnya lebih mudah untuk menulis program yang kuat set -e. Itu tidak memiliki jenis (berguna) ruang nama, modul, atau struktur data bersarang. Bug adalah kesulitan nomor satu dalam pemrograman; sementara kemudahan menulis program bebas bug tidak selalu merupakan faktor penentu dalam memilih bahasa, peringkat bash buruk pada hitungan itu. Bash juga mendapat peringkat buruk pada kinerja ketika melakukan hal-hal selain menggabungkan program bersama.

Untuk waktu yang lama bash tidak berjalan di Windows, dan bahkan hari ini bash tidak ada di instalasi Windows default, dan itu tidak berjalan sepenuhnya secara native (bahkan di WSL) dalam arti bahwa bash tidak memiliki antarmuka untuk Fitur asli Windows. Bash tidak berjalan di iOS dan tidak diinstal secara default di Android. Jadi, kecuali Anda sedang menulis aplikasi khusus Unix, bash sama sekali tidak portabel.

Membutuhkan kompiler bukan masalah untuk portabilitas. Kompiler berjalan di mesin pengembang. Membutuhkan perpustakaan juru bahasa atau pihak ketiga bisa menjadi masalah, tetapi di Linux itu adalah masalah yang dipecahkan melalui paket distribusi, dan di bawah Windows, Android dan iOS, orang-orang biasanya menggabungkan komponen pihak ketiga dalam paket aplikasi mereka. Jadi jenis kekhawatiran portabilitas yang Anda pikirkan bukan masalah praktis untuk aplikasi run-of-the-mill.

Jawaban saya berlaku untuk cangkang selain bash. Beberapa detail bervariasi dari shell ke shell tetapi ide umumnya sama.


1
Saya percaya mitos portabilitas telah cukup sering dibicarakan, tidak yakin saya akan menggunakan item tertentu sebagai negatif karena itu berlaku untuk sebagian besar bahasa lain juga, termasuk Jawa. Bahkan PHP yang berjalan di server windows vs server * nix memiliki beberapa perbedaan kecil yang harus selalu Anda perhatikan, jika Anda cukup bodoh untuk menjalankan apa pun di server windows, itu. Banyak hal yang tidak berjalan di android atau iOs jadi tidak yakin bagaimana itu bisa menjadi komentar yang valid juga.
Lizardx

7

Beberapa alasan untuk tidak menggunakan skrip shell untuk program besar, lepas dari kepala saya:

  • Sebagian besar fungsi dilakukan dengan mengabaikan perintah eksternal, yang lambat. Sebaliknya, bahasa pemrograman seperti Perl dapat melakukan hal yang setara mkdiratau secara grepinternal.
  • Tidak ada cara mudah untuk mengakses perpustakaan C, atau membuat panggilan sistem langsung, yang berarti bahwa misalnya gim video akan sulit dibuat
  • Bahasa pemrograman yang tepat memiliki dukungan yang lebih baik untuk struktur data yang kompleks. Meskipun Bash memang memiliki susunan dan susunan asosiatif, tetapi saya tidak ingin memikirkan daftar yang ditautkan atau pohon.
  • Shell dibuat untuk memproses perintah yang dibuat jika teks. Data biner (yaitu, variabel yang mengandung byte NUL (byte dengan nilai nol)) sulit untuk ditangani. Tergantung sedikit pada shell, zshmemiliki beberapa dukungan. Ini juga karena antarmuka untuk program eksternal sebagian besar berbasis teks, dan \0digunakan sebagai pemisah.
  • Juga karena perintah eksternal, pemisahan antara kode dan data sedikit sulit. Saksikan semua masalah yang ada saat mengutip data ke shell lain (yaitu ketika menjalankan bash -c ...atau ssh -c ...)

Ini adalah set negatif yang paling akurat bagi saya, sebagai seseorang yang melakukan banyak skrip bash besar, ini kira-kira akan menjadi apa yang saya sebut negatif juga. Namun, satu hal yang saya temukan adalah bahwa Bash sebenarnya tidak jauh lebih lambat daripada bahasa yang dikompilasi ketika membandingkan fungsi yang sama. Saya memiliki kecurigaan yang menyelinap bahwa saya harus mencoba untuk menulis beberapa hal yang lebih rumit yang saya miliki di bash dengan python, perbedaan kecepatan tidak akan membuat pekerjaan mengerikan yang terlibat layak dilakukan. Namun, Bash sendiri yang saya temukan terlalu terbatas, tetapi Bash + gawk berfungsi dengan baik, gawk hampir nyata.
Lizardx
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.