Saat Anda menggunakan pengolah kata, memformat teks sehingga baris akan sesuai dengan ruang yang tersedia pada perangkat target seharusnya tidak menjadi masalah. Tetapi ketika bekerja di terminal, segalanya tidak semudah itu.
Tentu saja, Anda selalu dapat memutuskan garis dengan tangan menggunakan editor teks favorit Anda, tetapi ini jarang diinginkan dan bahkan tidak mungkin untuk pemrosesan otomatis.
Semoga, POSIX fold
utilitas dan GNU/BSD fmt
perintah dapat membantu Anda untuk mengatur ulang teks sehingga garis tidak akan melebihi panjang tertentu.
Apa itu baris lagi di Unix?
Sebelum masuk ke detail fold
dan fmt
perintah, mari kita definisikan dulu apa yang sedang kita bicarakan. Dalam file teks, sebuah baris dibuat dari jumlah karakter yang berubah-ubah, diikuti oleh urutan kontrol baris baru khusus (kadang-kadang disebut EOL, untuk end-of-line )
Pada sistem mirip Unix, urutan kontrol akhir baris dibuat dari (satu-satunya) karakter umpan baris , kadang disingkat LF atau ditulis \n
mengikuti konvensi yang diwarisi dari bahasa C. Pada tingkat biner, karakter umpan baris direpresentasikan sebagai byte yang memegang 0a
nilai heksadesimal.
Anda dapat dengan mudah memeriksanya menggunakan hexdump
utilitas yang akan kita gunakan banyak dalam artikel ini. Jadi itu mungkin kesempatan yang baik untuk membiasakan diri dengan alat itu. Anda dapat, misalnya, memeriksa dump heksadesimal di bawah ini untuk menemukan berapa banyak karakter baris baru yang telah dikirim oleh setiap perintah gema. Setelah Anda merasa memiliki solusinya, coba lagi perintah tersebut tanpa | hexdump -C
bagian untuk melihat apakah Anda menebaknya dengan benar.
sh$ echo hello | hexdump -C
00000000 68 65 6c 6c 6f 0a |hello.|
00000006
sh$ echo -n hello | hexdump -C
00000000 68 65 6c 6c 6f |hello|
00000005
sh$ echo -e 'hello\n' | hexdump -C
00000000 68 65 6c 6c 6f 0a 0a |hello..|
00000007
Perlu disebutkan pada titik ini sistem operasi yang berbeda dapat mengikuti aturan yang berbeda mengenai urutan baris baru. Seperti yang telah kita lihat di atas, sistem operasi mirip Unix menggunakan line feed karakter, tetapi Windows, seperti kebanyakan protokol Internet, menggunakan dua karakter:carriage return+line feed pasangan (CRLF, atau 0d 0a
, atau \r\n
). Pada Mac OS "klasik" (hingga dan termasuk MacOS 9.2 di awal 2000-an), komputer Apple menggunakan CR saja sebagai karakter baris baru. Komputer lama lainnya juga menggunakan pasangan LFCR, atau bahkan urutan byte yang sama sekali berbeda dalam kasus sistem lama yang tidak kompatibel dengan ASCII. Untungnya, yang terakhir adalah peninggalan masa lalu, dan saya ragu Anda akan melihat komputer EBCDIC yang digunakan saat ini!
Berbicara tentang sejarah, jika Anda penasaran, penggunaan karakter kontrol "carriage return" dan "line feed" berasal dari kode Baudot yang digunakan di era teletype. Anda mungkin pernah melihat teletype yang digambarkan dalam film-film lama sebagai antarmuka ke komputer berukuran ruangan. Tetapi bahkan sebelum itu, teletype digunakan "berdiri sendiri" untuk komunikasi point-to-point atau multi-point. Pada saat itu, terminal tipikal tampak seperti mesin tik berat dengan keyboard mekanis, kertas, dan kereta bergerak yang memegang kepala cetak. Untuk memulai baris baru kereta harus dibawa kembali ke paling kiri, dan kertas harus bergerak ke atas dengan memutar pelat (kadang-kadang disebut "silinder"). Kedua gerakan itu dikendalikan oleh dua sistem elektromekanis independen, karakter kontrol pengumpanan garis dan pembawa kembali yang disambungkan langsung ke dua bagian perangkat tersebut. Karena memindahkan carriage membutuhkan waktu lebih lama daripada memutar pelat, logis untuk memulai carriage return terlebih dahulu. Memisahkan kedua fungsi juga memiliki beberapa efek samping yang menarik, seperti memungkinkan pencetakan berlebih (dengan hanya mengirimkan CR) atau transmisi efisien "interline ganda" (satu CR + dua LF).
Definisi di awal bagian ini sebagian besar menggambarkan apa yang logis garis adalah. Namun, sebagian besar waktu, baris logis yang "panjang sewenang-wenang" itu harus dikirim pada fisik perangkat seperti layar atau printer, di mana ruang yang tersedia terbatas. Menampilkan garis logis pendek pada perangkat yang memiliki garis fisik lebih besar tidak menjadi masalah. Cukup ada ruang yang tidak terpakai di sebelah kanan teks. Tetapi bagaimana jika Anda mencoba menampilkan sebaris teks yang lebih besar dari ruang yang tersedia di perangkat? Sebenarnya, ada dua solusi, masing-masing dengan kekurangannya:
- Pertama, perangkat dapat memotong garis pada ukuran fisiknya, sehingga menyembunyikan sebagian konten kepada pengguna. Beberapa printer melakukannya, terutama printer bodoh (dan ya, masih ada printer dot matrix dasar yang digunakan saat ini, terutama di lingkungan yang keras atau kotor!)
- Opsi kedua untuk menampilkan garis logis yang panjang adalah dengan membaginya menjadi beberapa garis fisik. Ini disebut pembungkus baris karena garis tampaknya membungkus ruang yang tersedia, efek yang sangat terlihat jika Anda dapat mengubah ukuran tampilan seperti saat bekerja dengan emulator terminal.
Perilaku otomatis tersebut cukup berguna, tetapi ada kalanya Anda ingin memutus antrean panjang pada posisi tertentu terlepas dari ukuran fisik perangkat. Misalnya, ini mungkin berguna karena Anda ingin jeda baris terjadi pada posisi yang sama baik di layar maupun di printer. Atau karena Anda ingin teks Anda digunakan dalam aplikasi yang tidak melakukan pembungkusan baris (misalnya, jika Anda secara terprogram menyematkan teks dalam file SVG). Akhirnya, percaya atau tidak, masih banyak protokol komunikasi yang memaksakan lebar saluran maksimum dalam transmisi, termasuk yang populer seperti IRC dan SMTP (jika Anda pernah melihat kesalahan 550 Panjang saluran maksimum melebihi Anda tahu apa yang saya membicarakan tentang). Jadi, ada banyak kesempatan di mana Anda perlu memecah antrean panjang menjadi potongan-potongan yang lebih kecil. Ini adalah tugas dari POSIX fold
perintah.
Perintah lipat
Saat digunakan tanpa opsi apa pun, tombol fold
perintah menambahkan urutan kontrol baris baru tambahan untuk memastikan tidak ada baris yang melebihi batas 80 karakter. Untuk memperjelas, satu baris paling banyak berisi 80 karakter ditambah urutan baris baru.
Jika Anda telah mengunduh materi pendukung untuk artikel tersebut, Anda dapat mencobanya sendiri:
sh$ fold POSIX.txt | head -5
The Portable Operating System Interface (POSIX)[1] is a family of standards spec
ified by the IEEE Computer Society for maintaining compatibility between operati
ng systems. POSIX defines the application programming interface (API), along wit
h command line shells and utility interfaces, for software compatibility with va
riants of Unix and other operating systems.[2][3]
# Using AWK to prefix each line by its length:
sh$ fold POSIX.txt | awk '{ printf("%3d %s\n", length($0), $0) }'
80 The Portable Operating System Interface (POSIX)[1] is a family of standards spec
80 ified by the IEEE Computer Society for maintaining compatibility between operati
80 ng systems. POSIX defines the application programming interface (API), along wit
80 h command line shells and utility interfaces, for software compatibility with va
49 riants of Unix and other operating systems.[2][3]
0
80 The standards emerged from a project that began circa 1985. Richard Stallman sug
80 gested the name POSIX to the IEEE instead of former IEEE-IX. The committee found
71 it more easily pronounceable and memorable, and thus adopted it.[2][4]
Anda dapat mengubah panjang garis keluaran maksimum dengan menggunakan -w
pilihan. Yang lebih menarik mungkin adalah penggunaan -s
opsi untuk memastikan garis akan putus pada batas kata. Mari kita bandingkan hasilnya tanpa dan dengan -s
opsi ketika diterapkan pada paragraf kedua dari contoh teks kami:
# Without `-s` option: fold will break lines at the specified position
# Broken lines have exactly the required width
sh$ awk -vRS='' 'NR==2' POSIX.txt |
fold -w 30 | awk '{ printf("%3d %s\n", length($0), $0) }'
30 The standards emerged from a p
30 roject that began circa 1985.
30 Richard Stallman suggested the
30 name POSIX to the IEEE instea
30 d of former IEEE-IX. The commi
30 ttee found it more easily pron
30 ounceable and memorable, and t
21 hus adopted it.[2][4]
# With `-s` option: fold will break lines at the last space before the specified position
# Broken lines are shorter or equal to the required width
awk -vRS='' 'NR==2' POSIX.txt |
fold -s -w 30 | awk '{ printf("%3d %s\n", length($0), $0) }'
29 The standards emerged from a
25 project that began circa
23 1985. Richard Stallman
28 suggested the name POSIX to
27 the IEEE instead of former
29 IEEE-IX. The committee found
29 it more easily pronounceable
24 and memorable, and thus
17 adopted it.[2][4]
Jelas, jika teks Anda berisi kata-kata yang lebih panjang dari panjang baris maksimum, perintah fold tidak akan dapat mengikuti -s
bendera. Dalam hal ini, fold
utilitas akan memecahkan kata-kata yang terlalu besar pada posisi maksimum, selalu memastikan tidak ada garis yang melebihi lebar maksimum yang diizinkan.
sh$ echo "It's Supercalifragilisticexpialidocious!" | fold -sw 10
It's
Supercalif
ragilistic
expialidoc
ious!
Karakter multibyte
Seperti kebanyakan, jika tidak semua, utilitas inti, fold
perintah dirancang pada satu waktu satu karakter setara dengan satu byte. Namun, hal ini tidak lagi terjadi dalam komputasi modern, terutama dengan adopsi UTF-8 yang meluas. Sesuatu yang mengarah ke masalah yang tidak menguntungkan:
# Just in case, check first the relevant locale
# settings are properly defined
debian-9.4$ locale | grep LC_CTYPE
LC_CTYPE="en_US.utf8"
# Everything is OK, unfortunately...
debian-9.4$ echo élève | fold -w2
é
l�
�v
e
Kata “élève” (bahasa Prancis untuk “siswa”) mengandung dua huruf beraksen:é
(Huruf KECIL LATIN E DENGAN AKUT) dan è
(Huruf KECIL LATIN E DENGAN KUburan). Dengan menggunakan set karakter UTF-8, huruf-huruf tersebut dikodekan menggunakan masing-masing dua byte (masing-masing, c3 a9
dan c3 a8
), alih-alih hanya satu byte seperti halnya untuk huruf Latin yang tidak beraksen. Anda dapat memeriksanya dengan memeriksa byte mentah menggunakan hexdump
kegunaan. Anda harus dapat menentukan urutan byte yang sesuai dengan é
dan è
karakter. Omong-omong, Anda juga dapat melihat di dump teman lama kita karakter feed baris yang kode heksadesimalnya disebutkan sebelumnya:
debian-9.4$ echo élève | hexdump -C
00000000 c3 a9 6c c3 a8 76 65 0a |..l..ve.|
00000008
Mari kita periksa sekarang output yang dihasilkan oleh perintah fold:
debian-9.4$ echo élève | fold -w2
é
l�
�v
e
debian-9.4$ echo élève | fold -w 2 | hexdump -C
00000000 c3 a9 0a 6c c3 0a a8 76 0a 65 0a |...l...v.e.|
0000000b
Jelas, hasil yang dihasilkan oleh fold
perintah sedikit lebih panjang dari string karakter asli karena baris baru tambahan:masing-masing panjang 11 byte dan panjang 8 byte, termasuk baris baru. Omong-omong, dalam output fold
perintah Anda mungkin telah melihat umpan baris (0a
) karakter yang muncul setiap dua byte. Dan inilah masalahnya:perintah fold memutus baris pada byte posisi, bukan karakter posisi. Bahkan jika jeda itu terjadi di tengah karakter multi-byte! Tidak perlu menyebutkan output yang dihasilkan bukan lagi aliran byte UTF-8 yang valid, oleh karena itu penggunaan Karakter Pengganti Unicode (�
) oleh terminal saya sebagai pengganti urutan byte yang tidak valid.
Like untuk cut
perintah yang saya tulis beberapa minggu yang lalu, ini adalah batasan dalam implementasi GNU dari fold
utilitas dan ini jelas bertentangan dengan spesifikasi POSIX yang secara eksplisit menyatakan bahwa “Sebuah garis tidak boleh putus di tengah karakter.”
Sehingga muncul GNU fold
implementasi hanya berurusan dengan benar dengan pengkodean karakter satu byte dengan panjang tetap (US-ASCII, Latin1, dan seterusnya). Sebagai solusinya, jika kumpulan karakter yang sesuai ada, Anda dapat mentranskode teks Anda ke pengkodean karakter satu byte sebelum memprosesnya, dan mentranskodekannya kembali ke UTF-8 sesudahnya. Namun, ini rumit, untuk sedikitnya:
debian-9.4$ echo élève |
iconv -t latin1 | fold -w 2 |
iconv -f latin1 | hexdump -C
00000000 c3 a9 6c 0a c3 a8 76 0a 65 0a |..l...v.e.|
0000000a
debian-9.4$ echo élève |
iconv -t latin1 | fold -w 2 |
iconv -f latin1
él
èv
e
Semua itu cukup mengecewakan, saya memutuskan untuk memeriksa perilaku implementasi lain. Seperti yang sering terjadi, implementasi OpenBSD dari fold
utilitas jauh lebih baik dalam hal ini karena sesuai dengan POSIX dan akan menghormati LC_CTYPE
pengaturan lokal untuk menangani karakter multi-byte dengan benar:
openbsd-6.3$ locale | grep LC_CTYPE
LC_CTYPE=en_US.UTF-8
openbsd-6.3$ echo élève | fold -w 2 C
él
èv
e
openbsd-6.3$ echo élève | fold -w 2 | hexdump -C
00000000 c3 a9 6c 0a c3 a8 76 0a 65 0a |..l...v.e.|
0000000a
Seperti yang Anda lihat, implementasi OpenBSD memotong garis dengan benar pada karakter posisi, terlepas dari jumlah byte yang diperlukan untuk mengkodekannya. Dalam sebagian besar kasus penggunaan, inilah yang Anda inginkan. Namun jika Anda memerlukan perilaku warisan (yaitu:gaya GNU) dengan mempertimbangkan satu byte sebagai satu karakter, Anda dapat untuk sementara mengubah lokal saat ini ke apa yang disebut lokal POSIX (diidentifikasi dengan "POSIX" konstan atau, untuk alasan historis, "C ”):
openbsd-6.3$ echo élève | LC_ALL=C fold -w 2
é
l�
�v
e
openbsd-6.3$ echo élève | LC_ALL=C fold -w 2 | hexdump -C
00000000 c3 a9 0a 6c c3 0a a8 76 0a 65 0a |...l...v.e.|
0000000b
Terakhir, POSIX menentukan -b
flag, yang menginstruksikan fold
utilitas untuk mengukur panjang garis dalam byte , tapi itu tetap menjamin karakter multi-byte (sesuai dengan LC_CTYPE
saat ini pengaturan lokal) akan tidak rusak.
Sebagai latihan, saya sangat menganjurkan Anda untuk meluangkan waktu yang diperlukan untuk menemukan perbedaan pada tingkat byte antara hasil yang diperoleh dengan mengubah lokal saat ini ke "C" (di atas), dan hasil yang diperoleh dengan menggunakan -b
bendera sebagai gantinya (di bawah). Ini mungkin halus. Tapi ada ada perbedaan:
openbsd-6.3$ echo élève | fold -b -w 2 | hexdump -C
00000000 c3 a9 0a 6c 0a c3 a8 0a 76 65 0a |...l....ve.|
0000000b
Jadi, apakah Anda menemukan perbedaannya?
Nah, dengan mengubah lokal menjadi “C”, fold
utilitas tidak memperhatikan urutan multi-byte— karena, menurut definisi, ketika lokal adalah "C", alat harus mengasumsikan satu karakter adalah satu byte . Jadi baris baru dapat ditambahkan di mana saja, bahkan di tengah urutan byte yang akan telah dianggap sebagai karakter multi-byte dalam pengkodean karakter lain. Inilah yang terjadi ketika alat menghasilkan c3 0a a8
urutan byte:dua byte c3 a8
dipahami sebagai satu karakter ketika LC_CTYPE
mendefinisikan pengkodean karakter menjadi UTF-8. Tetapi urutan byte yang sama terlihat sebagai dua karakter di lokal "C":
# Bytes are bytes. They don't change so
# the byte count is the same whatever is the locale
openbsd-6.3$ printf "%d bytes\n" $(echo -n é | LC_ALL=en_US.UTF-8 wc -c)
2 bytes
openbsd-6.3$ printf "%d bytes\n" $(echo -n é | LC_ALL=C wc -c)
2 bytes
# The interpretation of the bytes may change depending on the encoding
# so the corresponding character count will change
openbsd-6.3$ printf "%d chars\n" $(echo -n é | LC_ALL=en_US.UTF-8 wc -m)
1 chars
openbsd-6.3$ printf "%d chars\n" $(echo -n é | LC_ALL=C wc -m)
2 chars
Sebaliknya, dengan -b
opsi, alat harus tetap waspada multi-byte. Opsi itu hanya mengubah cara menghitung posisi , dalam byte kali ini, bukan dalam karakter seperti secara default. Dalam hal ini, karena urutan multi-byte tidak dipecah, output yang dihasilkan tetap menjadi aliran karakter yang valid (menurut LC_CTYPE
saat ini). pengaturan lokal):
openbsd-6.3$ echo élève | fold -b -w 2
é
l
è
ve
Anda telah melihatnya, sekarang tidak ada lagi kemunculan Karakter Pengganti Unicode (�
), dan kami tidak kehilangan karakter yang berarti dalam proses— dengan mengorbankan kali ini berakhir dengan baris yang berisi sejumlah karakter variabel dan sejumlah variabel byte. Terakhir, semua alat memastikan tidak ada lebih banyak byte per baris daripada yang diminta dengan -w
pilihan. Sesuatu yang dapat kita periksa menggunakan wc
alat:
openbsd-6.3$ echo élève | fold -b -w 2 | while read line; do
> printf "%3d bytes %3d chars %s\n" \
> $(echo -n $line | wc -c) \
> $(echo -n $line | wc -m) \
> $line
> done
2 bytes 1 chars é
1 bytes 1 chars l
2 bytes 1 chars è
2 bytes 2 chars ve
Sekali lagi, luangkan waktu yang dibutuhkan untuk mempelajari contoh di atas. Itu menggunakan printf
dan wc
perintah yang tidak saya jelaskan secara detail sebelumnya. Jadi, jika ada yang kurang jelas, jangan ragu untuk menggunakan kolom komentar untuk meminta penjelasan!
Karena penasaran, saya memeriksa -b
tandai pada kotak Debian saya menggunakan GNU fold
implementasi:
debian-9.4$ echo élève | fold -w 2 | hexdump -C
00000000 c3 a9 0a 6c c3 0a a8 76 0a 65 0a |...l...v.e.|
0000000b
debian-9.4$ echo élève | fold -b -w 2 | hexdump -C
00000000 c3 a9 0a 6c c3 0a a8 76 0a 65 0a |...l...v.e.|
0000000b
Jangan habiskan waktu Anda untuk mencari perbedaan antara -b
dan non--b
versi contoh itu:kami telah melihat implementasi lipatan GNU tidak menyadari multi-byte, jadi kedua hasilnya identik. Jika Anda tidak yakin akan hal itu, mungkin Anda bisa menggunakan diff -s
perintah untuk membiarkan komputer Anda mengkonfirmasinya. Jika Anda melakukannya, silakan gunakan bagian komentar untuk membagikan perintah yang Anda gunakan dengan pembaca lain!
Lagi pula, apakah itu artinya -b
opsi tidak berguna dalam implementasi GNU dari fold
kegunaan? Nah, dengan membaca lebih teliti dokumentasi GNU Coreutils untuk fold
perintah, saya menemukan -b
opsi hanya berurusan dengan karakter khusus seperti tab atau backspace yang masing-masing menghitung posisi 1~8 (satu hingga delapan) atau -1 (minus satu) dalam mode normal, tetapi mereka selalu menghitung 1 posisi dalam mode byte. Membingungkan? Jadi, mungkin kami bisa meluangkan waktu untuk menjelaskannya lebih detail.
Penanganan tab dan backspace
Sebagian besar file teks yang akan Anda tangani hanya berisi karakter yang dapat dicetak dan urutan akhir baris. Namun, terkadang, beberapa karakter kontrol dapat menemukan jalannya ke data Anda. Karakter tab (\t
) adalah salah satunya. Jauh lebih jarang, spasi mundur (\b
) juga dapat ditemui. Saya masih menyebutkannya di sini karena, seperti namanya, ini adalah karakter kontrol yang membuat kursor bergerak satu posisi mundur (ke kiri), sedangkan sebagian besar karakter lain membuatnya maju (ke kanan).
sh$ echo -e 'tab:[\t] backspace:[\b]'
tab:[ ] backspace:]
Ini mungkin tidak terlihat di browser Anda, jadi saya sangat menganjurkan Anda untuk mengujinya di terminal Anda. Tapi karakter tab (\t
) menempati beberapa posisi pada output. Dan ruang belakang? Sepertinya ada sesuatu yang aneh di outputnya, bukan? Jadi biarkan sedikit memperlambat, dengan memecah string teks menjadi beberapa bagian, dan memasukkan beberapa sleep
antara mereka:
# For that to work, type all the commands on the same line
# or using backslashes like here if you split them into
# several (physical) lines:
sh$ echo -ne 'tab:[\t] backspace:['; \
sleep 1; echo -ne '\b'; \
sleep 1; echo -n ']'; \
sleep 1; echo ''
OKE? Apakah Anda melihatnya kali ini? Mari kita uraikan urutan kejadiannya:
- Rangkaian karakter pertama ditampilkan “normal” hingga kurung buka kedua. Karena
-n
bendera,echo
perintah tidak tidak mengirim karakter baris baru, sehingga kursor tetap pada baris yang sama. - Tidur pertama.
- Backspace dikeluarkan, mengakibatkan kursor bergerak mundur satu posisi. Masih belum ada baris baru, jadi kursor tetap berada di baris yang sama.
- Tidur kedua.
- Kurung kurung kotak penutup ditampilkan, menimpa yang pertama.
- Tidur ketiga.
- Dengan tidak adanya
-n
opsi terakhirecho
perintah akhirnya mengirimkan karakter baris baru dan kursor bergerak ke baris berikutnya, di mana prompt shell Anda akan ditampilkan.
Tentu saja, efek keren yang serupa dapat diperoleh dengan menggunakan carriage return, jika Anda mengingatnya:
sh$ echo -n 'hello'; sleep 1; echo -e '\rgood bye'
good bye
Saya cukup yakin Anda telah melihat beberapa utilitas baris perintah seperti curl
, wget
atau ffmpeg
menampilkan bilah kemajuan. Mereka melakukan sihir mereka menggunakan kombinasi \b
dan/atau \r
.
Untuk menarik diskusi itu sendiri, intinya di sini adalah untuk memahami bahwa menangani karakter tersebut dapat menjadi tantangan untuk fold
kegunaan. Mudah-mudahan, standar POSIX mendefinisikan aturan:
Semua perlakuan khusus tersebut dinonaktifkan saat menggunakan -b
pilihan. Dalam hal ini, karakter kontrol di atas semuanya dihitung (dengan benar) untuk satu byte dan dengan demikian meningkatkan penghitung posisi satu dan hanya satu— sama seperti karakter lainnya.
Untuk pemahaman yang lebih baik, saya membiarkan Anda menyelidiki sendiri dua contoh berikut (mungkin menggunakan hexdump
kegunaan). Anda sekarang harus dapat menemukan mengapa "halo" menjadi "neraka" dan di mana tepatnya "i" di output (seperti yang ada, bahkan jika Anda tidak dapat melihatnya!) Seperti biasa, jika Anda membutuhkan bantuan , atau hanya jika Anda ingin membagikan temuan Anda, bagian komentar adalah milik Anda.
# Why "hello" has become "hell"? where is the "i"?
sh$ echo -e 'hello\rgood bi\bye' | fold -w4
hell
good
bye
# Why "hello" has become "hell"? where is the "i"?
# Why the second line seems to be made of only two chars instead of 4?
sh$ echo -e 'hello\rgood bi\bye' | fold -bw4
hell
go
od b
ye
Batasan lainnya
fold
perintah yang telah kita pelajari sampai sekarang dirancang untuk memecah garis logis yang panjang menjadi garis fisik yang lebih kecil, terutama untuk tujuan pemformatan.
Itu berarti mengasumsikan setiap jalur input mandiri dan dapat diputus secara independen dari jalur lainnya. Hal ini tidak selalu terjadi, namun. Misalnya, mari kita pertimbangkan email yang sangat penting yang saya terima:
sh$ cat MAIL.txt
Dear friends,
Have a nice day!
We are manufactuer for event chairs and tables, more than 10 years experience.
We supply all kinds of wooden, resin and metal event chairs, include chiavari
chairs, cross back chairs, folding chairs, napoleon chairs, phoenix chairs, etc.
Our chairs and tables are of high quality and competitively priced.
If you need our products, welcome to contact me;we are happy to make you special
offer.
Best Regards
Doris
sh$ awk '{ length>maxlen && (maxlen=length) } END { print maxlen }' MAIL.txt
81
Jelas, garis sudah dipecah menjadi beberapa lebar tetap. awk
perintah memberitahu saya lebar baris maksimum di sini adalah ... 81 karakter— tidak termasuk urutan baris baru. Ya, itu cukup aneh sehingga saya memeriksanya kembali:memang garis terpanjang memiliki 80 karakter yang dapat dicetak ditambah satu spasi tambahan di posisi ke-81 dan baru setelah itu ada karakter umpan baris. Mungkin orang IT yang bekerja atas nama "produsen" kursi ini dapat mengambil manfaat dari membaca artikel ini!
Bagaimanapun, dengan asumsi saya ingin mengubah format email itu, saya akan memiliki masalah dengan fold
perintah karena jeda baris yang ada. Saya membiarkan Anda memeriksa dua perintah di bawah ini sendiri jika Anda mau, tetapi tidak satupun dari mereka akan bekerja seperti yang diharapkan:
sh$ fold -sw 100 MAIL.txt
sh$ fold -sw 60 MAIL.txt
Yang pertama tidak akan melakukan apa-apa karena semua baris sudah lebih pendek dari 100 karakter. Mengenai perintah kedua, itu akan mematahkan garis pada posisi ke-60 tetapi tetap mempertahankan karakter baris baru yang sudah ada sehingga hasilnya akan bergerigi. Ini akan sangat terlihat di paragraf ketiga:
sh$ awk -v RS='' 'NR==3' MAIL.txt |
fold -sw 60 |
awk '{ length>maxlen && (maxlen=length); print length, $0 }'
53 We supply all kinds of wooden, resin and metal event
25 chairs, include chiavari
60 chairs, cross back chairs, folding chairs, napoleon chairs,
20 phoenix chairs, etc.
Baris pertama dari paragraf ketiga terputus pada posisi 53, yang konsisten dengan lebar maksimum 60 karakter per baris. Namun, baris kedua pecah di posisi 25 karena karakter baris baru itu sudah ada di file masukan. Dengan kata lain, untuk mengubah ukuran paragraf dengan benar, pertama-tama kita perlu menggabungkan kembali garis sebelum memecahnya di posisi target yang baru.
Anda dapat menggunakan sed
atau awk
untuk bergabung kembali dengan garis. Dan faktanya, seperti yang saya sebutkan di video pengantar, itu akan menjadi tantangan yang bagus untuk Anda ambil. Jadi jangan ragu untuk memposting solusi Anda di bagian komentar.
Untuk saya sendiri, saya akan mengikuti jalan yang lebih mudah dengan melihat fmt
memerintah. Meskipun bukan perintah standar POSIX, ini tersedia di dunia GNU dan BSD. Jadi ada kemungkinan bagus itu akan dapat digunakan di sistem Anda. Sayangnya, kurangnya standarisasi akan memiliki beberapa implikasi negatif seperti yang akan kita lihat nanti. Tapi untuk saat ini, mari kita berkonsentrasi pada bagian yang baik.
Perintah fmt
fmt
perintah lebih berkembang daripada fold
perintah dan memiliki lebih banyak opsi pemformatan. Bagian yang paling menarik adalah dapat mengidentifikasi paragraf dalam file input berdasarkan baris kosong. Itu berarti semua baris hingga baris kosong berikutnya (atau akhir file) pertama-tama akan digabungkan untuk membentuk apa yang saya sebut sebelumnya sebagai "garis logis" dari teks. Baru setelah itu, fmt
perintah akan memecah teks pada posisi yang diminta.
Mari kita lihat sekarang apa yang akan berubah ketika diterapkan pada paragraf kedua dari contoh surat saya:
sh$ awk -v RS='' 'NR==3' MAIL.txt |
fmt -w 60 |
awk '{ length>maxlen && (maxlen=length); print length, $0 }'
60 We supply all kinds of wooden, resin and metal event chairs,
59 include chiavari chairs, cross back chairs, folding chairs,
37 napoleon chairs, phoenix chairs, etc.
Secara anekdot, fmt
perintah diterima untuk mengemas satu kata lagi di baris pertama. Tapi yang lebih menarik, baris kedua sudah terisi, artinya karakter baris baru sudah ada di file input setelah kata “chiavari” (apa ini?) dibuang. Tentu saja, semuanya tidak sempurna, dan fmt
algoritma pendeteksian paragraf terkadang memicu kesalahan positif, seperti dalam salam di akhir surat (baris 14 dari output):
sh$ fmt -w 60 MAIL.txt | cat -n
1 Dear friends,
2
3 Have a nice day! We are manufactuer for event chairs and
4 tables, more than 10 years experience.
5
6 We supply all kinds of wooden, resin and metal event chairs,
7 include chiavari chairs, cross back chairs, folding chairs,
8 napoleon chairs, phoenix chairs, etc.
9
10 Our chairs and tables are of high quality and competitively
11 priced. If you need our products, welcome to contact me;we
12 are happy to make you special offer.
13
14 Best Regards Doris
Tadi saya bilang fmt
command adalah alat pemformatan teks yang lebih berkembang daripada fold
kegunaan. Memang itu. Ini mungkin tidak terlihat jelas pada pandangan pertama, tetapi jika Anda perhatikan dengan seksama baris 10-11, Anda mungkin melihatnya menggunakan dua spasi setelah titik— menegakkan konvensi yang paling banyak dibahas tentang penggunaan dua spasi di akhir kalimat. Saya tidak akan membahas perdebatan itu untuk mengetahui apakah Anda harus atau tidak menggunakan dua spasi di antara kalimat tetapi Anda tidak punya pilihan nyata di sini:sepengetahuan saya, tidak ada implementasi umum fmt
perintah menawarkan bendera untuk menonaktifkan spasi ganda setelah kalimat. Kecuali opsi seperti itu ada di suatu tempat dan saya melewatkannya? Jika ini masalahnya, saya akan senang Anda memberi tahu saya tentang hal itu menggunakan bagian komentar:sebagai penulis Prancis, saya tidak pernah menggunakan “spasi ganda” setelah kalimat…
Opsi fmt lainnya
fmt
utilitas dirancang dengan beberapa kemampuan pemformatan lebih dari perintah lipat. Namun, karena tidak didefinisikan POSIX, ada ketidakcocokan utama antara opsi GNU dan BSD.
Misalnya, -c
option digunakan di dunia BSD untuk memusatkan teks sedangkan di fmt
GNU Coreutils ini mengaktifkan mode margin mahkota, “mempertahankan lekukan dua baris pertama dalam paragraf, dan menyelaraskan margin kiri setiap baris berikutnya dengan baris kedua. “
Saya membiarkan Anda bereksperimen sendiri dengan GNU fmt -c
jika kamu mau. Secara pribadi, saya menemukan fitur pemusatan teks BSD lebih menarik untuk dipelajari karena beberapa keanehan:memang, di OpenBSD, fmt -c
will center the text according to the target width— but without reflowing it! So the following command will not work as you might have expected:
openbsd-6.3$ fmt -c -w 60 MAIL.txt
Dear friends,
Have a nice day!
We are manufactuer for event chairs and tables, more than 10 years experience.
We supply all kinds of wooden, resin and metal event chairs, include chiavari
chairs, cross back chairs, folding chairs, napoleon chairs, phoenix chairs, etc.
Our chairs and tables are of high quality and competitively priced.
If you need our products, welcome to contact me;we are happy to make you special
offer.
Best Regards
Doris
If you really want to reflow the text for a maximum width of 60 characters and center the result, you will have to use two instances of the fmt
perintah:
openbsd-6.3$ fmt -w 60 MAIL.txt | fmt -c -w60
Dear friends,
Have a nice day! We are manufactuer for event chairs and
tables, more than 10 years experience.
We supply all kinds of wooden, resin and metal event chairs,
include chiavari chairs, cross back chairs, folding chairs,
napoleon chairs, phoenix chairs, etc.
Our chairs and tables are of high quality and competitively
priced. If you need our products, welcome to contact me;we
are happy to make you special offer.
Best Regards Doris
I will not make here an exhaustive list of the differences between the GNU and BSD fmt
implementations … essentially because all the options are different! Except of course the -w
pilihan. Speaking of that, I forgot to mention -N
where N is an integer is a shortcut for -wN
. Moreover you can use that shortcut both with the fold
and fmt
commands:so, if you were perseverent enough to read his article until this point, as a reward you may now amaze your friends by saving one (!) entire keystroke the next time you will use one of those utilities:
debian-9.4$ fmt -50 POSIX.txt | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified
by the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface
openbsd-6.3$ fmt -50 POSIX.txt | head -5
The Portable Operating System Interface (POSIX)[1]
is a family of standards specified by the IEEE
Computer Society for maintaining compatibility
between operating systems. POSIX defines the
application programming interface (API), along
debian-9.4$ fold -sw50 POSIX.txt | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified by
the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface
openbsd-6.3$ fold -sw50 POSIX.txt | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified by
the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface
As the final word, you may also notice in that last example the GNU and BSD versions of the fmt
utility are using a different formatting algorithm, producing a different result. On the other hand, the simpler fold
algorithm produces consistent results between the implementations. All that to say if portability is a premium, you need to stick with the fold
command, eventually completed by some other POSIX utilities. But if you need more fancy features and can afford to break compatibility, take a look at the manual for the fmt
command specific to your own system. And let us know if you discovered some fun or creative usage for those vendor-specific options!