Interaksi sistem

Menjalankan perintah sistem dengan system dan backtick, menangkap status keluar, dan dasar IPC melalui open.

Daftar isi

Topik ini membahas cara skrip Perl menjalankan perintah sistem dan memperoleh hasilnya. Pembahasan mencakup fungsi system untuk mengeksekusi perintah, pembacaan kode keluar melalui variabel $?, penangkapan keluaran dengan backtick, serta pembacaan aliran keluaran perintah melalui open dengan mode -|. Setelah topik ini diikuti, skrip dapat mengatur langkah berikutnya berdasarkan keberhasilan perintah eksternal yang dipanggilnya, bukan sekadar memanggilnya dan berharap semuanya berjalan lancar.

Menjalankan perintah dengan system#

Fungsi system menjalankan perintah eksternal, menunggunya selesai, lalu melanjutkan skrip. Bentuk yang disarankan adalah daftar argumen, yaitu perintah dan setiap argumennya diberikan sebagai nilai yang terpisah. Dengan bentuk ini, perl memanggil perintahnya secara langsung tanpa perantara shell, sehingga karakter khusus pada argumen tidak pernah ditafsirkan sebagai perintah shell. Keluaran perintah tetap menuju keluaran standar terminal, sedangkan nilai balik system adalah status perintahnya.

perl jalankan-sistem.pl
#!/usr/bin/perl
use strict;
use warnings;

# memanggil perintah dengan daftar argumen, tanpa shell
system("echo", "Arsip cadangan dimulai");

# system mengembalikan 0 apabila perintah berhasil
my $status = system("true");
print "Status balik true: $status\n";

# perintah yang berakhir dengan kegagalan memberi nilai bukan nol
$status = system("false");
print "Status balik false: $status\n";
text Keluaran
Arsip cadangan dimulai
Status balik true: 0
Status balik false: 256

Nilai balik system mengikuti konvensi yang sering mengejutkan pemula, yaitu 0 berarti berhasil. Pada skrip di atas, perintah true selalu berakhir dengan kode keluar 0, sehingga system mengembalikan 0. Perintah false berakhir dengan kode keluar 1, dan nilai yang diterima skrip adalah 256, yaitu kode keluar 1 yang digeser ke kiri sebanyak delapan bit. Nilai mentah tersebut dibaca kembali pada bagian berikutnya untuk memperoleh kode keluarnya.

Membaca kode keluar dengan $?#

Setiap proses yang dijalankan meninggalkan statusnya pada variabel khusus $?. Nilai itu dibungkus dalam struktur status yang lebih besar, sehingga kode keluar yang sesungguhnya diperoleh dengan menggesernya delapan bit ke kanan, yaitu $? >> 8. Pola ini digunakan ketika skrip perlu menindaklanjuti kode tertentu, misalnya mencatat nomor error dari proses pembuatan arsip cadangan yang gagal.

perl status-keluar.pl
#!/usr/bin/perl
use strict;
use warnings;

# menjalankan perl kecil yang berakhir dengan kode 3
system("perl", "-e", "exit 3");

print "Kode keluar anak: ", ($? >> 8), "\n";
text Keluaran
Kode keluar anak: 3

Perintah perl -e "exit 3" dipilih karena kode keluarnya pasti 3 pada setiap eksekusi, sehingga hasil penggeseran bitnya mudah diperiksa. Nilai yang dicetak sesuai dengan kode yang diberikan oleh proses anak, tanpa bagian struktur status yang lain. Pemisahan struktur inilah alasan penggeseran bit diperlukan sebelum nilai $? dibandingkan dengan angka yang diharapkan.

Struktur status tersebut menyimpan informasi tambahan di luar kode keluarnya. Delapan bit terendah menyimpan nomor sinyal yang menghentikan proses, sehingga $? & 127 bernilai nol selama proses anak berakhir secara normal. Bit dengan nilai 128 menandai proses yang berhenti dengan core dump, dan ujiannya ditulis $? & 128. Pola yang sama berlaku pada nilai balik system karena nilai itu juga berupa status mentah sebelum digeser.

Variabel $? selalu ditimpa oleh proses yang dijalankan berikutnya. Setiap pemanggilan system, backtick, serta close pada pipe memperbarui variabel yang sama. Apabila pemeriksaannya baru dilakukan setelah beberapa perintah berjalan, nilainya perlu disalin ke variabel lain lebih dahulu.

Menangkap keluaran dengan backtick#

Backtick mengeksekusi perintah dan mengembalikan seluruh keluaran standarnya sebagai string. Berbeda dengan system, hasilnya tidak langsung menuju terminal, melainkan disimpan ke variabel untuk diproses lebih lanjut. Perintah pada backtick dijalankan melalui shell, sehingga penulisan dengan tanda kutip di dalamnya diterima sebagaimana perintah yang diketik pada terminal. Karena keluaran perintah umumnya berakhir dengan karakter baris baru, fungsi chomp memangkasnya sebelum teks digunakan.

perl tangkap-backtick.pl
#!/usr/bin/perl
use strict;
use warnings;

# backtick menangkap keluaran standar perintah
my $keluaran = `echo "Kapasitas arsip 40 persen"`;
chomp $keluaran;
print "Diterima: $keluaran\n";

# hasil tangkapan diproses seperti string biasa
my $panjang = length $keluaran;
print "Panjang teks: $panjang karakter\n";
text Keluaran
Diterima: Kapasitas arsip 40 persen
Panjang teks: 25 karakter

Perbedaan utama system dan backtick terletak pada kebutuhan skrip. Apabila hanya keberhasilan perintah yang penting, system lebih tepat karena keluarannya tidak menumpuk di memori. Apabila isi keluarannya perlu dibaca, misalnya kapasitas arsip yang akan dibandingkan dengan ambang batas, backtick menyediakan nilai itu tanpa perantara tambahan.

Teks di dalam backtick mengalami interpolasi variabel sebagaimana string dengan tanda kutip ganda, sehingga isi variabel Perl dapat disambungkan ke perintahnya. Interpolasi ini perlu diwaspadai ketika perintahnya memuat karakter $ milik shell, karena perl memproses variabelnya lebih dahulu. Operator qx menyediakan pilihan pemisah yang lebih luas, dan pemisah berupa tanda kutip tunggal menonaktifkan interpolasi tersebut. Backtick sendiri merupakan bentuk singkat dari operator yang sama.

Keluaran yang ditangkap hanya aliran STDOUT, sedangkan STDERR tetap menuju terminal tanpa melalui variabel. Status berakhirnya perintah tetap tercatat pada $?, sehingga keberhasilannya dapat diperiksa setelah penangkapan. Dalam konteks daftar, backtick mengembalikan satu butir untuk setiap baris keluaran, lengkap dengan karakter baris barunya.

Membaca keluaran perintah dengan open#

Fungsi open dengan mode -| menjalankan perintah dan menghubungkan keluarannya ke filehandle yang dapat dibaca baris demi baris. Bentuknya sama dengan open tiga argumen yang digunakan pada modul Berkas dan I/O, hanya saja argumen kedua berisi -| dan argumen ketiganya berupa daftar perintah. Aliran data diproses seiring perintahnya berjalan, sehingga skrip dapat menanggapi setiap baris tanpa menunggu seluruh keluaran selesai. Sama seperti bentuk daftar argumen pada system, pemanggilan ini juga menempuh jalur tanpa shell.

perl baca-pipe.pl
#!/usr/bin/perl
use strict;
use warnings;

# membuka perintah untuk dibaca, sebagaimana berkas
open(my $proses, '-|', 'perl', '-e', 'print "baris satu\nbaris dua\n"')
    or die "Tidak dapat menjalankan perintah: $!";

while (my $baris = <$proses>) {
    print "diterima: $baris";
}

close($proses);
text Keluaran
diterima: baris satu
diterima: baris dua

Setelah perulangan selesai, close menutup pipe dan mengembalikan status perintahnya. Apabila perintah berakhir dengan error, close mengembalikan nilai salah dan kode keluarnya dapat dibaca dari $? dengan pola yang sama seperti pada system. Pada contoh ini keluarannya hanya dua baris, tetapi bentuk open semacam ini tetap menjadi pilihan ketika aliran yang diharapkan panjang, karena barisnya diproses selagi perintahnya masih berjalan.

Bentuk daftar perintah tidak menyediakan fitur shell, sehingga tanda bintang untuk globbing atau tanda pipa antarperintah diperlakukan sebagai argumen biasa. Apabila fitur tersebut benar-benar diperlukan, perl menyediakan bentuk satu string yang dijalankan melalui shell, dengan konsekuensi penanganan karakter khususnya menjadi tanggung jawab penulis skrip. Pilihan ini mengikuti pola yang sama dengan dua bentuk pemanggilan system.

Mode -| mengalirkan data dari keluaran perintah ke filehandle, sedangkan mode kebalikannya, yaitu |-, menghubungkan keluaran standar skrip ke masukan perintah. Dengan mode |-, pernyataan print ke filehandle menjadi masukan bagi perintah yang dijalankan. Kedua mode ditutup dengan close, dan status perintahnya dilaporkan pada $?.

Memilih alat yang sesuai#

Ketiga mekanisme di atas saling melengkapi, dan pilihannya ditentukan oleh bentuk informasi yang dibutuhkan skrip.

KebutuhanMekanisme
Menjalankan perintah, membiarkan keluarannya tampil, lalu memeriksa statusnyasystem
Menangkap seluruh keluaran pendek sebagai satu stringbacktick
Membaca keluaran yang panjang baris demi baris selagi perintah berjalanopen dengan mode baca perintah

system tetap menjadi pilihan awal untuk perintah yang hasilnya tidak dibaca skrip, misalnya pembuatan arsip cadangan. Backtick menyederhanakan penangkapan keluaran yang pendek, sedangkan mode baca perintah menjaga penggunaan memori tetap kecil pada keluaran yang panjang karena barisnya dapat dibuang setelah diproses. Ketiganya sama-sama meninggalkan status proses pada $?, sehingga penanganan kegagalannya mengikuti pola yang sama.

Jalannya perintah juga membedakan ketiganya. Backtick selalu menyerahkan perintahnya kepada shell, sedangkan bentuk daftar argumen pada system dan mode -| pada open memanggil perintahnya secara langsung. Oleh karena itu, data dari luar skrip lebih aman diberikan melalui bentuk daftar, karena karakter khususnya tidak pernah ditafsirkan sebagai perintah shell. Ketiganya bersifat sinkron, sehingga skrip menunggu perintahnya selesai sebelum melanjutkan pernyataan berikutnya.

Ketiga mekanisme tersebut mengalirkan informasi satu arah saja, yaitu dari keluaran perintah menuju skrip. Apabila skrip perlu menulis ke masukan perintah sekaligus membaca keluarannya, perl menyediakan modul IPC::Open2 dengan komunikasi dua arah semacam itu. Kebutuhan dua arah jarang muncul pada skrip pemeriksaan rutin, sehingga ketiga alat di atas mencakup sebagian besar kebutuhan.

Kesalahan umum#

  1. Keluaran backtick langsung dibandingkan dengan string yang diharapkan tanpa melalui chomp, sehingga perbandingan selalu salah karena karakter baris baru masih melekat. Perbaikannya adalah memangkas nilai tangkapan dengan chomp sebelum digunakan atau diproses lebih lanjut.
  2. Status proses dibaca langsung dari $? tanpa penggeseran bit, sehingga nilai yang diperiksa berupa 256, 512, dan seterusnya, bukan 1, 2, dan seterusnya. Perbaikannya adalah membaca $? >> 8 pada setiap pemeriksaan kode keluar.
  3. Hasil perintah diharapkan tampil di layar setelah dipanggil dengan backtick, padahal nilainya sedang ditahan di variabel. Kesalahan yang serupa terjadi ketika system dianggap mengembalikan teksnya, padahal yang dikembalikan adalah status. Bedakan kedua fungsinya berdasarkan kebutuhan, yaitu backtick untuk membaca keluaran dan system untuk memeriksa status.

Ringkasan#

  • system menjalankan perintah dengan daftar argumen tanpa perantara shell dan mengembalikan 0 apabila perintah berhasil.
  • Kode keluar perintah dibaca dari $? >> 8, dan nilai itu menentukan tindak lanjut skrip terhadap keberhasilan atau kegagalan.
  • Backtick menangkap seluruh keluaran standar perintah sebagai string, sehingga perlu chomp sebelum digunakan.
  • open dengan mode -| membaca keluaran perintah baris demi baris melalui filehandle, sedangkan close mengembalikan status perintahnya.

Referensi#