Uji berkas

Operator uji berkas -e, -f, dan -d untuk memeriksa keberadaan, jenis, dan izin berkas sebelum diakses.

Daftar isi

Topik ini membahas operator uji berkas, yaitu kumpulan operator satu huruf berawalan tanda hubung yang memeriksa keberadaan, jenis, izin, dan ukuran berkas tanpa membuka berkasnya. Pembahasan mencakup operator -e, -f, dan -d sebagai inti, kemudian -r, -w, -z, dan -s sebagai pelengkap. Setelah seluruh contoh diikuti, skrip dapat memilih tindakannya berdasarkan kondisi berkas di penyimpanan sebelum pemanggilan open dilakukan.

Mengenal operator uji berkas#

Operator uji berkas (file test operator) ditulis satu huruf setelah tanda hubung, misalnya -e, dan diikuti nama atau jalur berkas yang diperiksa. Operator itu mengembalikan nilai benar bila pengujian lolos dan nilai salah bila tidak, sehingga bentuk pemakaiannya paling alami berada di dalam percabangan if. Pengujian tidak mengubah berkasnya sama sekali, karena hanya membaca informasi dari sistem berkas. Operator yang paling sering digunakan dirangkum pada tabel berikut.

OperatorPengujian
-eEntri dengan nama tersebut ada, baik berkas maupun direktori.
-fEntri tersebut berupa berkas biasa.
-dEntri tersebut berupa direktori.
-rBerkas dapat dibaca oleh pengguna yang menjalankan skrip.
-wBerkas dapat ditulis oleh pengguna yang menjalankan skrip.
-zBerkas ada tetapi kosong, yaitu ukurannya nol byte.
-sMengembalikan ukuran berkas dalam byte, atau nilai salah bila berkas kosong atau tidak ada.

Satu pengujian sudah cukup untuk keputusan sederhana, sedangkan beberapa operator dapat digabung dalam satu percabangan bila syaratnya lebih dari satu, misalnya keberadaan sekaligus izin baca. Pola seperti inilah yang digunakan untuk menjaga skrip dari kegagalan open yang sebetulnya sudah dapat diduga sejak awal.

Memeriksa keberadaan dengan -e#

Operator -e menguji keberadaan entri pada jalur yang diberikan, dan merupakan pengujian pertama sebelum sebuah berkas dibaca. Cabang yang mengikuti pengujian ini menentukan arah program, misalnya membaca berkas bila ada atau membuatnya bila belum. Skrip berikut menyiapkan satu berkas contoh berisi satu baris, kemudian menguji keberadaan berkas itu dan berkas yang sengaja tidak dibuat, lengkap dengan pengujian kosong dan ukuran:

perl uji-keberadaan.pl
#!/usr/bin/perl
use strict;
use warnings;

# menyiapkan berkas contoh yang isinya satu baris
open(my $fh, '>', 'hasil-sensor.txt')
    or die "Tidak dapat membuat hasil-sensor.txt: $!";
print $fh "2024-05-06 07:00 24.1\n";
close($fh);

# memeriksa keberadaan berkas
if (-e 'hasil-sensor.txt') {
    print "hasil-sensor.txt ada\n";
}

if (-e 'laporan-hilang.txt') {
    print "laporan-hilang.txt ada\n";
} else {
    print "laporan-hilang.txt tidak ada\n";
}

# memeriksa apakah berkosong
if (-z 'hasil-sensor.txt') {
    print "hasil-sensor.txt kosong\n";
} else {
    print "hasil-sensor.txt berisi data\n";
}

# mengambil ukuran berkas dalam byte
my $ukuran = -s 'hasil-sensor.txt';
print "Ukuran berkas: $ukuran byte\n";
text Keluaran
hasil-sensor.txt ada
laporan-hilang.txt tidak ada
hasil-sensor.txt berisi data
Ukuran berkas: 22 byte

Pengujian pada laporan-hilang.txt memperlihatkan cabang else berjalan bila berkasnya tidak ada, sehingga program tetap menghasilkan keluaran yang rapi tanpa error. Operator -z melengkapi -e, karena berkas yang ada tetapi kosong sering perlu diperlakukan berbeda dari berkas yang berisi data. Operator -s mengembalikan angka, sehingga nilainya disimpan dalam variabel dan ditampilkan pada baris terakhir keluaran.

Secara mekanisme, -e menanyakan keberadaan entri kepada sistem berkas melalui pemanggilan sistem stat, sehingga jalur berupa tautan simbolik (symlink) dinilai pada sasaran akhirnya, bukan pada tautannya. Tautan yang menunjuk entri yang sudah hilang menghasilkan nilai salah karena sasarannya tidak ditemukan. Hasil stat juga disimpan untuk digunakan ulang oleh filehandle khusus _, sehingga pola if (-e $berkas and -f _) memeriksa keberadaan lalu jenis berkasnya tanpa mengulangi pemanggilan sistem. Pola semacam ini berguna bila keberadaan dan jenis harus dipastikan bersamaan sebelum berkas dibuka.

Membedakan berkas biasa dan direktori#

Operator -f dan -d menguji jenis entri. Nilai kembalian -f benar hanya untuk berkas biasa, sedangkan -d benar hanya untuk direktori, dan keduanya saling meniadakan pada satu jalur yang sama. Pembedaan ini penting karena fungsi open bekerja pada berkas, sedangkan penelusuran isi memerlukan direktori, sehingga jenis entri menentukan tindakan yang sah.

Skrip berikut menyiapkan satu berkas dan satu direktori contoh, lalu membedakan keduanya dengan -f dan -d, termasuk uji silang yang diharapkan tidak lolos:

perl uji-jenis.pl
#!/usr/bin/perl
use strict;
use warnings;

# menyiapkan satu berkas contoh
open(my $fh, '>', 'suhu-terkini.txt')
    or die "Tidak dapat membuat suhu-terkini.txt: $!";
print $fh "24.1\n";
close($fh);

# menyiapkan satu direktori contoh
my $dir = 'arsip-cadangan';
if (not -d $dir) {
    mkdir $dir, 0755 or die "Tidak dapat membuat direktori $dir: $!";
}

# membedakan berkas biasa dan direktori
print "suhu-terkini.txt adalah berkas biasa\n" if -f 'suhu-terkini.txt';
print "arsip-cadangan adalah direktori\n" if -d 'arsip-cadangan';

# uji silang yang diharapkan tidak lolos
print "suhu-terkini.txt BUKAN direktori\n" unless -d 'suhu-terkini.txt';
print "arsip-cadangan BUKAN berkas biasa\n" unless -f 'arsip-cadangan';

# memeriksa izin baca dan tulis
print "suhu-terkini.txt dapat dibaca\n" if -r 'suhu-terkini.txt';
print "suhu-terkini.txt dapat ditulis\n" if -w 'suhu-terkini.txt';
text Keluaran
suhu-terkini.txt adalah berkas biasa
arsip-cadangan adalah direktori
suhu-terkini.txt BUKAN direktori
arsip-cadangan BUKAN berkas biasa
suhu-terkini.txt dapat dibaca
suhu-terkini.txt dapat ditulis

Empat baris pertama keluaran memperlihatkan peran -f dan -d beserta uji silangnya, sedangkan dua baris terakhir memperlihatkan pemeriksaan izin. Pada contoh juga terlihat bentuk penulisan ringkas berupa pernyataan print yang diikuti pengubah if -f atau unless -d, yaitu percabangan satu baris yang menjalankan pernyataannya hanya bila pengujian lolos. Pembuatan direktori pada contoh dijaga oleh not -d $dir, sehingga mkdir hanya dipanggil bila direktorinya memang belum ada dan skrip tetap dapat dijalankan berulang kali.

Hasil -f dan -d berasal dari jenis entri pada hasil stat, sehingga entri khusus seperti FIFO (named pipe) dan socket bernilai salah untuk keduanya. Apabila nama yang diuji berasal dari pembacaan isi direktori, nama dasar tersebut harus digabung dengan jalur direktorinya terlebih dahulu, karena pengujian dijalankan relatif terhadap direktori kerja saat ini. Operator -d juga lolos pada tautan simbolik yang menunjuk direktori, karena stat mengikuti tautan sampai ke sasarannya. Dengan sifat tersebut, pengujian jenis memberi hasil yang sama pada jalur langsung maupun jalur yang melalui tautan.

Memeriksa izin dan ukuran berkas#

Operator -r dan -w menguji izin baca dan tulis berkas terhadap pengguna yang menjalankan skrip. Hasilnya bergantung pada pemilik berkas dan izin yang disetel sistem operasi, sehingga skrip dapat memilih tindakan yang realistis, misalnya membaca arsip yang hanya boleh dibaca tanpa mencoba menulisnya ulang. Operator -z dan -s menangani sisi ukuran, yaitu membedakan berkas kosong dari berkas berisi data dan mengambil ukurannya dalam byte.

Beberapa pengujian digabung bila syaratnya majemuk. Pola berikut hanya membuka berkas bila berkasnya ada dan dapat dibaca sekaligus:

perl Contoh: menggabungkan dua uji berkas
# tidak-dijalankan
if (-e $nama and -r $nama) {
    open(my $fh, '<', $nama) or die "Tidak dapat membuka $nama: $!";
}

Pengujian awal semacam ini membuat pesan program lebih informatif, tetapi tidak menggantikan pemeriksaan kegagalan pada open. Kondisi berkas dapat berubah di antara pengujian dan pembukaan, dan izin dapat menolak dengan cara yang tidak terduga, sehingga or die tetap dipertahankan sebagai pagar terakhir.

Kedua uji izin membandingkan izin berkas dengan identitas efektif proses, yaitu pengguna (uid) dan grup (gid) yang menjalankan interpreter. Bentuk dengan huruf kapital -R dan -W menguji identitas nyata, dan perbedaannya terasa hanya bila identitas efektif berbeda dari identitas nyata, misalnya pada skrip setuid. Apabila skrip dijalankan oleh pengguna root, uji baca dan tulis lolos untuk hampir semua berkas biasa karena kernel mengizinkan root mengakses berkas apa pun. Untuk ukuran, -s mengembalikan nilai tidak terdefinisi apabila pemanggilan stat gagal, misalnya karena berkasnya tidak ada, sehingga hasilnya diperiksa dengan defined sebelum digunakan dalam perhitungan.

Kesalahan umum#

Kesalahan pertama adalah menganggap -e yang lolos berarti berkas pasti dapat dibuka. Keberadaan berkas tidak menjamin izinnya, sehingga open tetap dapat gagal dan disiplin or die tetap wajib pada setiap pemanggilan.

Kesalahan kedua adalah menggunakan -f untuk menguji direktori atau -d untuk menguji berkas. Kedua operator menuntut jenis entri yang tepat, dan uji silang pada skrip uji-jenis.pl memperlihatkan hasil yang tidak lolos bila jenisnya tertukar. Periksa maksud pengujian lebih dahulu, yaitu keberadaan dengan -e, berkas biasa dengan -f, dan direktori dengan -d.

Kesalahan ketiga adalah menulis jalur yang keliru pada pengujian, misalnya jalur dengan spasi yang tidak dikutip atau nama yang salah ketik. Hasilnya selalu salah, dan program menyimpulkan berkasnya tidak ada padahal ada. Jalur yang disimpan dalam variabel dan diuji dengan -e pada berkas contoh, sebagaimana dilakukan skrip di atas, mengurangi kesalahan semacam ini.

Ringkasan#

  • Operator uji berkas seperti -e, -f, dan -d memeriksa kondisi berkas tanpa membukanya, dan hasilnya digunakan di dalam percabangan if.
  • Operator -e menguji keberadaan entri apa pun, -f khusus berkas biasa, dan -d khusus direktori, sehingga jenis entri dapat dibedakan sebelum diakses.
  • Operator -r dan -w menguji izin baca dan tulis, sedangkan -z menguji berkas kosong dan -s mengembalikan ukuran dalam byte.
  • Pengujian awal tidak menggantikan or die pada open, karena kondisi berkas dapat berubah dan izin dapat menolak di saat pemanggilan.

Referensi#