Optimisasi Mikro dan Portabilitas dalam Shell-script #2
Shell-scripting mindset shift pt. 2 of 7
I/O Redirection feat. IFS
cat
(bahkan piping ke grep
) untuk membaca
dan/atau mengurai file.
Namun, pernahkan kalian memanfaatkan penuh redirection operator untuk mengalihkan I/O di
beberapa shell seperti bash/zsh? Yap, merupakan salah satu fitur favorit penulis.Clobbering Output
Singkatnya, clobbering adalah proses menimpa data sepenuhnya pada file maupun processor register atau sebuah wilayah dari memori komputer. Kalian pasti sudah terbiasa menggunakannya.
|
|
POSIX.1-2017
Untuk mencengah clobbering, dapat dilakukan dengan mengatur parameter pada shell seperti set -o noclobber
di ksh, bash, dan zsh. Lalu, set noclobber
untuk csh dan tcsh. Sedangkan dash
menggunakan set -C
. Untuk mengatifkannya kembali, ubah karakter -
menjadi +
di opsi.
|
|
|
|
Namun, pengaturan parameter noclobber dapat diabaikan dengan operator >|
agar melewatinya.
POSIX juga mendefinisikan file descriptor yang diwakili dengan angka desimal, dimulai dari 0 (setidaknya) sampai 9 untuk digunakan. Nilai 0 (stdin), 1 (stdout), dan 2 (stderr) memiliki arti khusus dan penggunaan konvensional, serta tersirat oleh operasi pengalihan tertentu. Mereka disebut sebagai standard input, standard output, dan standard error. Biasanya, program mengambil input dari stdin, menulis output pada stdout, dan menulis pesan kesalahan (atau error) pada stderr. Selain nilai tersebut, digunakan spesifik untuk kasus tertentu dan biasanya kompleks seperti reverse shell.
File Standard Input
|
|
2nd line
POSIX.1-2017
Here Documents Input
|
|
EOL
, sehingga sintaks tidak diperlakukan sebagai string.2nd line
3rd line
POSIX.1-2017
Here Strings Input
|
|
Itu tidak didefinisikan oleh POSIX. Berlaku di ksh, bash, dan zsh. Bagaimana dengan shell yang lain?
Di zsh, tiga jenis input di atas dapat dieksekusi tanpa menggunakan perintah atau utilitas eksternal lain. Namun, di bash 4.4 atau lebih baru, itu perlu ditetapkan sebagai sebuah variabel terlebih dulu karena hanya mendukung di dalam substitusi perintah, serta hanya mendukung file standard input.
|
|
|
|
2nd line
Adapun untuk POSIX-compliant sh yang lain di mana tidak mendukung fitur tersebut, kita dapat
menggunakan perintah read
bawaan untuk membaca (dan/atau mengurai) setiap baris dalam file.
|
|
|
|
Bagaimana untuk membaca (dan/atau mengurai) file dengan banyak baris dengan perintah read
?
|
|
2nd line
|
|
2nd line
3rd line
Namun, teknik tersebut tidak disarankan jika baris dalam file sangat banyak karena prosesnya lambat, mengingat itu membaca dan menampilkan output tiap baris secara berulang (atau looping).
Specific Use-case Initiative
Nah, setelah membahas dasar yang biasa digunakan, apakah kalian bertanya-tanya bahwa beberapa utilitas atau
program tidak bekerja seperti apa yang diharapkan? Sebagai contoh, menggunakan heredocs
untuk mengecualikan file pada perintah rsync
dengan memanfaatkan file descriptor yang ada di
Linux walau hanya bekerja jika yang diinginkan adalah input tunggal.
|
|
Sebenarnya rsync
mendukung -
sebagai stdin atau stdout, itu tidak portabel antar program.
Untuk menggunakan output dari beberapa perintah sebagai input dari sebuah perintah tunggal, gunakanlah substitusi proses, itu akan membuat file descriptor khusus dan menggunakannya.
|
|
|
|
Itu tidak didefinisikan oleh POSIX. Berlaku di ksh86, bash, dan zsh. Bagaimana shell yang lain?
Satu lagi yang perlu diketahui bahwa perintah tee
(dari GNU coreutils) dapat menyalin input
ke stdout dan juga menulisnya ke (lebih dari satu) file secara bersama-sama (simultaneously).
|
|
|
|
/tmp/tee2: this line will be in various files and output
IFS Implementation of read
Sekarang, kita coba terapkan pada kasus nyata dengan memanfaatkan variabel internal $_ dan $IFS
untuk mengurai data yang ada dalam file. Sebagai contoh, kita uraikan file /proc/version
di Linux.
|
|
Kemudian, urai untuk mengambil versi rilis kernel di mana setiap string dipisahkan dengan spasi.
|
|
|
|
Seperti data awal yang disajikan, setiap string misalnya dari Linux ke version
dipisahkan dengan spasi. Lalu, kita tetapkan parameter $IFS dengan nilai karakter spasi agar
diperlakukan sebagai delimiter.
Secara default, nilai dari parameter $IFS adalah spasi, tab, dan newline. Parameter $IFS
sendiri sebenarnya berperilaku berbeda-beda di tiap sintaks. Karena kita membahas I/O redirection,
kita tidak akan menjelaskan secara komprehensif perbedaannya dan fokus dengan perintah read
.
Di dalam perintah read
. Jika beberapa nama variabel ditentukan sebagai argumennya maka $IFS digunakan
untuk membagi baris dari input, sehingga setiap variabel mendapatkan satu bidang dari input dan variabel
terakhir mendapatkan semua bidang yang tersisa (jika ada lebih banyak bidang daripada variabel). Sehingga,
untuk mengurai string Linux, version, dll (kita sebut bidang atau field) dengan delimiter
karakter spasi, kita tentukan 2 bidang tersebut dengan nama variabel internal $_ yang tidak memiliki
efek samping apa pun karena ditetapkan dari awal secara default. Sebenarnya bebas menentukan nama variabel
apa pun. Secara default, nilai dari parameter $_ ditetapkan secara terus-menerus seiring
perintah diinputkan dengan delimiter karakter spasi (atau pemisah argumen).
Contoh lain, kita uraikan file /proc/uptime
, pengganti perintah uptime -p
yang tidak portabel.
|
|
|
|
Jumlah detik sistem telah aktif | Jumlah detik total setiap core CPU saat sistem idle |
---|---|
20372.66 | 69096.54 |
Kemudian, urai dan proses dengan ekspansi aritmatika untuk menghasilkan format replika uptime.
|
|
|
|
|
|
|
|
|
|