Pendahuluan
Rename, atau mengganti nama file, adalah pekerjaan yang sering sekali harus kita lakukan. Saat ingin mereorganisasi dokumen-dokumen kita, seringkali kita harus mengubah lokasi direktori dan nama-nama file. Kadang-kadang sebuah program memberi nama otomatis pada sebuah file dan harus kita ganti. Dan, saat bertukar file dengan rekan atau mendownload dari Internet, seringkali nama filenya tidak cocok dengan selera kita.
Mengganti nama file lewat command line sampai saat ini tetap dapat menjadi salah satu pilihan favorit bagi Anda ketimbang lewat GUI, karena fleksibilitas dan programabilitasnya tak terkalahkan. Artikel ini ingin mendemokan mengapa demikian halnya, lewat contoh berbagai trik rename di command line dari dasar hingga lanjut.
Shell
Sintaks dasar perintah mv
Perintah dasar di shell untuk mengganti nama (dan/atau memindahkan) file adalah mv (singkatan dari move). Perintah ini dapat mengganti nama file menjadi nama lain dan/atau lokasi lain jika diberi 2 argumen:
$ mv NAMA1 NAMA2 $ mv NAMA1 LOKASI-LAIN/NAMA1
Perhatian: jika NAMA2 adalah sebuah file yang sudah ada, maka file tersebut akan tertimpa isinya.
Jika diberi lebih dari 2 argumen, maka argumen terakhir haruslah sebuah direktori tujuan (bukan file), dan efeknya adalah memindahkan file/direktori ke direktori tujuan tersebut. contoh:
$ mv FILE1 FILE2 FILE3 DIR1 DIR2 DIR-TUJUAN
Beberapa opsi perintah mv yang sering digunakan adalah -i (interactive) yang akan mengeluarkan pertanyaan konfirmasi untuk setiap file/direktori yang akan dipindahkan, dan -v (verbose) yang akan menampilkan setiap file/direktori yang sedang dipindahkan.
Mengganti nama file yang aneh
Untuk mengganti nama file yang aneh di command line, seperti biasa kita menggunakan fitur escaping dari shell. Misalnya, untuk nama file yang mengandung spasi kita dapat menggunakan kutip tunggal (‘) atau kutip ganda (“) atau meng-escape spasi dengan backslash (\). Contoh:
$ mv 'Aku cinta padamu.txt' "Mimpi di Jum'at siang.txt" lirik/ $ mv lirik/Aku\ cinta\ padamu.txt lirik/aku_cinta_padamu.txt
Catatan: Anda dapat menggunakan fasilitas tab completion sehingga shell otomatis akan menuliskan nama file lengkap, lengkap dengan escapingnya. Misalnya:
$ mv Aku<TAB>
Saat Anda menekan tombol Tab, maka otomatis shell akan menambahkan sehingga menjadi:
$ mv Aku\ cinta\ padamu.txt
Perbedaan kutip tunggal dan ganda adalah, di dalam kutip ganda substitusi variabel dan backtick masih berfungsi, contoh:
$ ls -1 hasil*
hasil tes 1.txt
hasil tes 2.txt
$ mv hasil\ tes\ 1.txt "hasil tes 1 - `date +%Y-%m-%d`".txt
$ mv hasil\ tes\ 2.txt 'hasil tes 2 - `date +%Y-%m-%d`'.txt
$ ls hasil*
hasil tes 1 - 2008-07-07.txt
hasil tes 2 - `date +%Y-%m-%d`.txt
Jika di dalam kutip ada kutip lagi, Anda dapat menggunakan backslash, kutip luar yang berbeda (seperti contoh sebelumnya), atau keluar dulu dari kutip dan menggunakan kutip yang berbeda:
$ mv Mimpi\ di\ Jum\'at\ siang.txt mimpi_di_jumat_siang.txt
$ mv "Mimpi di Jum'at siang.txt" mimpi_di_jumat_siang.txt
$ mv mimpi_di_jumat_siang.txt 'Mimpi di Jum'"'"'at siang.txt'
Perhatikan contoh terakhir. Untuk menulis kutip tunggal pada kata Jum’at, kita keluar dulu dari kutip tunggal sebelumnya, lalu menggunakan kutip ganda (“) untuk mengutip si kutip tunggal. Hasilnya memang agak sulit dibaca, tapi jenis kutip seperti ini kadang-kadang diperlukan.
Mengganti nama banyak file sekaligus
Misalnya kita ingin mengganti beberapa file yang tidak memiliki akhiran menjadi *.txt.
$ ls -1
1
2
13
40
Tujuan kita:
1.txt
2.txt
13.txt
40.txt
Seorang pemula mungkin akan langsung berpikiran:
$ mv * *.txt
Sayangnya, ini tidak bekerja karena wildcard * oleh shell akan diekspansi sehingga menjadi:
$ mv 1 2 13 40 *.txt
Seperti telah disebutkan sebelumnya, jika argumen perintah mv lebih dari 2 maka argumen terakhir haruslah direktori. Dengan demikian mv tidak mendukung penggantian banyak nama file sekaligus. Kita harus menggunakan looping di shell:
$ for f in *;do mv "$f" "$f".txt; done
Perhatikan kutip “” di atas, ini untuk menginstruksikan shell agar mengutip hasil ekspansi agar jika ditemukan file bernama aneh di variabel f (seperti spasi, kutip, dsb) tidak akan mengacaukan perintah mv.
Untuk melakukan penggantian selektif, kita tinggal menyesuaikan wildcard-nya saja. Misalnya, untuk hanya memroses file yang namanya terdiri dua huruf dan bukan satu:
$ for f in ??; do ...; done
Menukar 2 nama file
Menukar (swapping) dua nama file juga sesuatu yang sering perlu dilakukan. Umumnya algoritmanya adalah dengan melibatkan file sementara sbb:
$ mv FILE1 SEMENTARA
$ mv FILE2 FILE1
$ mv SEMENTARA FILE2
Sehingga efeknya adalah FILE1 menjadi FILE2 dan sebaliknya. Trik intinya adalah menghasilkan nama acak/sementara SEMENTARA yang tidak bentrok dengan file yang sudah ada. Untuk ini kita dapat menggunakan bantuan perintah tempfile:
$ temp=`tempfile --directory=.`; \
mv FILE1 $temp && mv FILE2 FILE1 && mv $temp FILE2
Catatan: kita menggunakan && agar jika terjadi kegagalan di satu step kita bisa langsung berhenti. Misalnya jika kita gagal mengubah FILE1 menjadi $temp, kita tidak mengganti FILE2 menjadi FILE1 sehingga berefek FILE1 tertimpa oleh FILE2.
Tip: Anda dapat membuat skrip sederhana seperti ini:
#!/bin/bash
if test $# -ne 2; then echo "Usage: $0 FILE1 FILE2"; exit 1; fi
temp=`tempfile --directory=.`
mv "$1" $temp && mv "$2" "$1" && mv $temp "$2"
lalu Anda beri nama misalnya tukar, sehingga di lain waktu Anda tidak perlu mengingat perintah rumit lagi melainkan hanya:
$ tukar FILE1 FILE2
Substitusi di nama file
Untuk mengganti nama file *.MP3 (huruf kapital) menjadi *.mp3 (huruf kecil), Anda dapat menggunakan sintaks seperti ini:
$ ls -1
satu.MP3
2.MP3
satu lagi.MP3
$ for f in *.MP3; do mv "$f" "${f/.MP3/.mp3}"; done
$ ls -1
satu.mp3
2.mp3
satu lagi.mp3
Sintaks bash:
${var/.../...}
akan melakukan substitusi pada variabel var yaitu mencari string dan diganti dengan string kedua. Detil mengenai sintaks ini dan beberapa sintaks ${…} lainnya dapat dibaca di manual bash (man bash).
Contoh yang lebih kompleks dengan shell
Tentu saja, Anda dapat menggunakan segala macam konstruksi shell yang tersedia dalam mengganti nama file. Misalnya, Anda ingin mereorganisasi file-file ke dalam direktori dengan awalan huruf pertamanya. Anda juga ingin mengkonversinya ke dalam huruf kecil semua. Tapi Anda tidak ingin mengganggu direktori. Yaitu:
0/
a/
b/
c/
...
z/
Aku cinta padamu.mp3
Tiren - cd1of2.avi
Tiren - cd2of2.avi
9 and a half weeks.MPG
menjadi:
0/9 and a half weeks.mpg
a/aku cinta padamu.mp3
t/tiren - cd1of2.avi
t/tiren - cd2of2.avi
...
Perintahnya:
$ for f in *;do
if test -f "$f"; then
hurufkecil="`echo "$f" | tr A-Z a-z`"
hurufawal="${hurufkecil:0:1}"
if test '!' -d "$hurufawal"; then hurufawal=0; fi
mv -v "$f" "$hurufawal/$hurufkecil"
fi
done
Dalam contoh di atas, selain looping (for), digunakan juga kondisi (if), pengecekan file (test), perintah tr, dan penggunaan variabel.
perlrename dan phprename
Pekerjaan yang semakin kompleks dan high level membutuhkan tool yang lebih kompleks dan high level pula. Sehari-hari, kecuali untuk pekerjaan mengganti nama yang paling sederhana, saya tidak lagi menggunakan perintah mv lagi melainkan menggunakan skrip perlrename. Bagi pembaca yang hanya familiar dengan PHP, saya membuatkan juga versi PHP-nya, phprename. Listing phprename dapat dilihat di Listing 1, untuk perlrename dapat didownload di website saya. Tentu saja Anda pun bebas membuat pythonrename, rubyrename, shellrename, dst.
[Listing 1]
Prinsip kerja dari skrip ini adalah, Anda cukup menyuplai sebuah kode kecil dalam bahasa Perl (atau PHP, …) yang mengubah satu variabel (di perlrename, $_ sementara di phprename $file). Variabel ini akan diisi dengan setiap nama file/direktori yang ingin diganti. Proses penggantian nama file, pengecekan penimpaan, pemrosesan rekursif, dsb akan dilakukan oleh skrip. Sehingga, Anda cukup berfokus pada proses inti yaitu penggantian nama file itu sendiri.
Keunggulan menggunakan skrip ini dibandingkan mv langsung adalah:
- lebih mudah/sederhana, cukup mengubah nilai variabel;
- dapat memanfaatkan seluruh fasilitas bahasa pemrograman yang umumnya lebih ekspresif dan bertenaga dibandingkan shell;
- ada mode rekursif (opsi -r);
- ada mode tes (opsi -d) untuk hanya mengetes dan tidak benar-benar melakukan penggantian nama file;
- untuk menghindari penimpaan, otomatis menambahkan akhiran .1, .2, dsb (kecuali jika diinstruksikan menimpa dengan opsi o);
- ada opsi (-f) untuk tidak mengacuhkan direktori;
Beberapa contoh sederhana
Mari lihat beberapa contoh sederhana penggunaan skrip ini. Kedua versi PHP dan Perl diberikan, silakan pilih salah satu. Tip: biasakan tambahkan dulu opsi -d untuk melakukan pengetesan, tidak betul-betul mengubah nama file. Jika hasilnya sudah terlihat betul, barulah hilangkan opsi -d.
Untuk mengganti semua file menjadi huruf kecil semua (umumnya sering harus dilakukan jika kita mengambil file dari DOS/CDROM/FTP server):
$ perlrename -e'$_ = lc' *
$ phprename -e'$file = strtolower($file);' *
Untuk mengganti semua file *.DAT menjadi *.mpg:
$ perlrename -e's/\.DAT$/.mpg/' *
$ phprename -e'$file = preg_replace("/\.DAT\$/", ".mpg", $file);' *
Contoh sebelumnya di shell (memindahkan file ke direktori sesuai nama awal filenya):
$ perlrename -fe'$_ = lc; ($hurufawal)=/(.)/;
$hurufawal !~ /[a-z]/ && $hurufawal="0";
$_ = "$hurufawal/$_"' *
$ phprename -fe'$file = strtolower($file);
$hurufawal = substr($file, 0, 1);
if ($hurufawal < "a" || $hurufawal > "z") $hurufawal = "0";
$file = "$hurufawal/$file";' *
Mengacak nama file
Kadang-kadang diperlukan jika Anda ingin memroses beberapa file tapi ingin urutannya diacak (tidak alfabetis) dan Anda tidak peduli nama filenya apa:
$ perlrename -de'$_ = rand' *
$ phprename -de'$file = md5($file);' *
Menyandikan nama file dengan uuencode atau mcrypt, iseng:
$ phprename -de'$file = preg_replace("#/#", "@",
base64_encode($file));' *
Catatan: enkoding base64 menghasilkan “/” yang merupakan pemisah path di Unix sehingga harus kita ganti misalnya dengan ‘@’.
Mengubah nama file menjadi angka
Kadang kita ingin mengubah banyak file menjadi nomor saja, dengan akhiran tetap (mis: satu.txt menjadi 0001.txt, dst).
$ perlrename -e '$i||=0; $i++ unless $TESTING;
/.+\.(.+)/; $ext=$1;
$ndig = @ARGV >= 1000 ? 4 : @ARGV >= 100 ? 3 : @ARGV >= 10 ? 2 : 1;
$_ = sprintf "%0${ndig}d%s", $i, (defined($ext) ? ".$ext" : "");' *
$ phprename -e'global $i, $args;
preg_match("/.+\.(.+)/", $file, $m);
if (!$TESTING) $i++;
$ndig = count($args) >= 1000 ? 4 : (count($args) >= 100 ? 3 :
(count($args) >= 10 ? 2 : 1));
$file = sprintf("%0{$ndig}d%s", $i, isset($m[1]) ? ".$m[1]" : "");' *
Memindahkan semua file ke direktori yang aktif
Skrip ini memindahkan semua file yang ada di subdirektori ke dalam direktori saat ini, berguna jika kita ingin mengumpulkan file yang tersebar di banyak subdirektori dan pegal jika harus dipindahkan satu persatu secara manual:
$ perlrename -dre'BEGIN {use Cwd; $cwd=getcwd if $TESTING}
$_="$cwd/$_" if -f' *
$ phprename -dre'global $i, $cwd;
if ($i++ == 0) { if ($TESTING) $cwd = getcwd(); }
if (is_file($file)) $file = "$cwd/$file";' *
Hasilnya:
1/1a.txt
1/2/2a.txt
1/2/2b.txt
1/1b.txt
1/sama.txt
3.txt
sama.txt
menjadi:
1a.txt
1b.txt
2a.txt
3.txt
sama.txt
sama.txt.1
Penggunaan variabel global dan kode if ($i++ == 0) di PHP, dan blok BEGIN {} di Perl di atas berguna agar kode yang diapitnya hanya dijalankan sekali saja (mis: untuk inisialisasi saja), tidak untuk setiap file yang akan diproses.
Menambah informasi ukuran file ke nama file
$ perlrename -de'
($name, $ext) = /(.+)\.(.+)/;
$_ = "$name (".(-s)." byte).$ext" *
Hasilnya:
notes.txt
dua.mp3
akan menjadi:
notes (268 byte).txt
dua (2392423 byte).mp3
Membersihkan nama file hasil download
Nama file hasil download, terutama dari jaringan P2P, kadang-kadang aneh atau macam-macam. Kita dapat melakukan pembersihan misalnya mengubah semua yang di luar [A-Za-z0-9_-] menjadi .:
$ phprename -de'$file = preg_replace("/[^A-Za-z0-9_-]+/", ".", $file);' *
Hasilnya:
Aku cinta padamu.mp3
[BARU] Wall-E (2008).avi
menjadi:
Aku.cinta.padamu.mp3
.BARU.Wall-E.2008.avi
Nama file sederhana seperti ini lebih mudah diketik dan tidak perlu dikutip/diescape, karenanya cukup popular dipakai orang.
Menghilangkan aksen. Nama-nama hasil download file dari Eropa misalnya Prancis, Jerman, dsb kadang juga mengandung karakter aksen/diakritik dan kadang agak bermasalah dalam ditangani. Untuk menghilangkannya:
$ perlrename -de'use Text::Unaccent; $_=unac_string("utf8", $_);
s/[^A-za-z0-9_-]/./g;' *
Hasilnya:
Céline Dion - Ce N'était Qu'un Rêve.mp3
Menjadi:
Celine Dion - Ce N'etait Qu'un Reve.mp3
Catatan: Skrip di atas membutuhkan modul Perl Text::Unaccent, yang dapat diinstal dengan cpan. tersedia juga program open source bernama detox untuk melakukan ini.
Karakter Mandarin. Mendownload file dengan karakter China juga kadang bermasalah. Kita dapat mengkonversinya menjadi latin, yaitu aksara pinyinnya:
perlrename -de'use Lingua::Han::PinYin; $h||=Lingua::Han::PinYin->new;
$_=$h->han2pinyin($_)' *
Contoh hasilnya:
liudehua - zhongguoren.mp3
Catatan: membutuhkan modul Perl Lingua::Han::PinYin.
Mengganti nama file multimedia
File musik dan video cukup sering harus kita ganti namanya, karena memang file-file itu yang paling sering didownload atau disharing. Untuk file musik saya juga membuat skrip yang sedikit lebih high-level yaitu perlmp3tag. Konsepnya mirip perlrename, tapi untuk setiap file skrip akan menyediakan juga metadata di variabel-variabel: $TITLE, $TRACK, $ARTIST, $ALBUM, $COMMENT, $YEAR, $GENRE. Sementara nama filenya sendiri di $FILE. Anda cukup menyuplai kode Perl untuk mengganti isi variabel $FILE (atau $TITLE, dsb).
Misalnya, untuk mengganti nama file musik menjadi berformat “ARTIST – ALBUM – TRACK – JUDUL.mp3”:
$ perlmp3tag -e'$FILE = sprintf("%s - %s - %02d - %s.mp3",
$ARTIST, $ALBUM, $TRACK, $TITLE)' *.mp3
Untuk mengganti tahun menjadi 2008 dan nama artis menjadi huruf kecil semua:
$ perlmp3tag -e'$YEAR = 2008; $ARTIST = lc($ARTIST)' *.mp3
Tentu saja, banyak aplikasi pemutar multimedia (termasuk Amarok, JuK) menyediakan fasilitas penggantian nama file musik secara masal, namun fleksibilitas yang kita peroleh lewat skrip lebih banyak.
Penutup
perlrename, phprename, perlmp3tag dapat didownload di: http://people.masterweb.net/steven/files/.
Pertanyaan atau komentar dapat dilayangkan ke penulis di <[email protected]>.