Beberapa orang memiliki gagasan keliru yang readmerupakan perintah untuk membaca sebuah baris. Ini bukan.
readmembaca kata-kata dari garis (mungkin garis miring terbalik), di mana kata-kata $IFSdibatasi dan garis miring terbalik dapat digunakan untuk menghindari pembatas (atau melanjutkan garis).
Sintaks generik adalah:
read word1 word2... remaining_words
readmembaca stdin satu byte pada suatu waktu sampai menemukan karakter newline tidak lolos (atau end-of-input), membagi bahwa menurut aturan yang kompleks dan menyimpan hasil membelah yang ke $word1, $word2... $remaining_words.
Misalnya pada input seperti:
<tab> foo bar\ baz bl\ah blah\
whatever whatever
dan dengan nilai default $IFS, read a b cakan menetapkan:
$a ⇐ foo
$b ⇐ bar baz
$c ⇐ blah blahwhatever whatever
Sekarang jika hanya melewati satu argumen, itu tidak menjadi read line. Itu masih read remaining_words. Pemrosesan backslash masih dilakukan, karakter spasi IFS masih dihapus dari awal dan akhir.
The -rpilihan menghilangkan pengolahan backslash. Jadi, perintah yang sama di atas dengan -rsebaliknya akan menetapkan
$a ⇐ foo
$b ⇐ bar\
$c ⇐ baz bl\ah blah\
Sekarang, untuk bagian pemisahan, penting untuk menyadari bahwa ada dua kelas karakter untuk $IFS: karakter spasi IFS (yaitu spasi dan tab (dan baris baru, meskipun di sini itu tidak masalah kecuali jika Anda menggunakan -d), yang juga terjadi berada di nilai default $IFS) dan yang lainnya. Perlakuan untuk dua kelas karakter berbeda.
Dengan IFS=:( :menjadi tidak karakter spasi IFS), masukan seperti :foo::bar::akan dipecah menjadi "", "foo", "", bardan ""(dan tambahan ""dengan beberapa implementasi meskipun itu tidak masalah kecuali read -a). Sementara jika kita menggantinya :dengan spasi, pemisahan dilakukan hanya menjadi foodan bar. Yang memimpin dan yang tertinggal diabaikan, dan urutannya diperlakukan seperti satu. Ada aturan tambahan saat karakter spasi dan non-spasi putih digabungkan $IFS. Beberapa implementasi dapat menambah / menghapus perlakuan khusus dengan menggandakan karakter di IFS ( IFS=::atau IFS=' ').
Jadi di sini, jika kita tidak ingin karakter spasi putih terkemuka dan tertinggal dilucuti, kita perlu menghapus karakter spasi putih IFS dari IFS.
Bahkan dengan karakter IFS-non-spasi putih, jika baris input berisi satu (dan hanya satu) karakter tersebut dan itu adalah karakter terakhir dalam baris (seperti IFS=: read -r wordpada input seperti foo:) dengan cangkang POSIX (bukan zshatau beberapa pdkshversi), input tersebut dianggap sebagai satu fookata karena dalam cangkang itu, karakter $IFSdianggap sebagai terminator , jadi wordakan berisi foo, bukan foo:.
Jadi, cara kanonik untuk membaca satu jalur input dengan readbuiltin adalah:
IFS= read -r line
(perhatikan bahwa untuk sebagian besar readimplementasi, yang hanya berfungsi untuk baris teks karena karakter NUL tidak didukung kecuali dalam zsh).
Menggunakan var=value cmdsintaks memastikan IFShanya diatur secara berbeda selama durasi cmdperintah itu.
Catatan sejarah
The readbuiltin diperkenalkan oleh Bourne shell dan sudah membaca kata-kata , bukan baris. Ada beberapa perbedaan penting dengan cangkang POSIX modern.
Shell Bourne readtidak mendukung -ropsi (yang diperkenalkan oleh shell Korn), jadi tidak ada cara untuk menonaktifkan pemrosesan backslash selain pra-pemrosesan input dengan sesuatu seperti di sed 's/\\/&&/g'sana.
Shell Bourne tidak memiliki gagasan tentang dua kelas karakter (yang sekali lagi diperkenalkan oleh ksh). Dalam Bourne shell semua karakter menjalani perlakuan yang sama seperti IFS karakter spasi lakukan di ksh, yaitu IFS=: read a b cpada input seperti foo::barakan menugaskan baruntuk $b, tidak string kosong.
Dalam cangkang Bourne, dengan:
var=value cmd
Jika cmdbuilt-in (seperti readada), vartetap diatur ke valuesetelah cmdselesai. Itu sangat penting dengan $IFSkarena dalam shell Bourne, $IFSdigunakan untuk membagi segalanya, tidak hanya ekspansi. Juga, jika Anda menghapus karakter spasi dari $IFSdalam Bourne shell, "$@"tidak lagi berfungsi.
Di shell Bourne, pengarahan ulang perintah majemuk menyebabkannya berjalan dalam subkulit (dalam versi paling awal, bahkan hal-hal suka read var < fileatau exec 3< file; read var <&3tidak berfungsi), jadi jarang di shell Bourne digunakan readuntuk apa pun selain input pengguna pada terminal (di mana penanganan kelanjutan garis itu masuk akal)
Beberapa Unices (seperti HP / UX, juga ada satu di dalamnya util-linux) masih memiliki lineperintah untuk membaca satu baris input (yang dulunya adalah perintah UNIX standar hingga Spesifikasi Single UNIX versi 2 ).
Itu pada dasarnya sama dengan head -n 1kecuali bahwa itu membaca satu byte pada suatu waktu untuk memastikan itu tidak membaca lebih dari satu baris. Pada sistem itu, Anda dapat melakukan:
line=`line`
Tentu saja, itu berarti memunculkan proses baru, menjalankan perintah dan membaca hasilnya melalui pipa, jadi jauh lebih efisien daripada ksh IFS= read -r line, tetapi masih jauh lebih intuitif.