Beberapa orang memiliki gagasan keliru yang read
merupakan perintah untuk membaca sebuah baris. Ini bukan.
read
membaca kata-kata dari garis (mungkin garis miring terbalik), di mana kata-kata $IFS
dibatasi dan garis miring terbalik dapat digunakan untuk menghindari pembatas (atau melanjutkan garis).
Sintaks generik adalah:
read word1 word2... remaining_words
read
membaca 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 c
akan 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 -r
pilihan menghilangkan pengolahan backslash. Jadi, perintah yang sama di atas dengan -r
sebaliknya 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"
, ""
, bar
dan ""
(dan tambahan ""
dengan beberapa implementasi meskipun itu tidak masalah kecuali read -a
). Sementara jika kita menggantinya :
dengan spasi, pemisahan dilakukan hanya menjadi foo
dan 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 word
pada input seperti foo:
) dengan cangkang POSIX (bukan zsh
atau beberapa pdksh
versi), input tersebut dianggap sebagai satu foo
kata karena dalam cangkang itu, karakter $IFS
dianggap sebagai terminator , jadi word
akan berisi foo
, bukan foo:
.
Jadi, cara kanonik untuk membaca satu jalur input dengan read
builtin adalah:
IFS= read -r line
(perhatikan bahwa untuk sebagian besar read
implementasi, yang hanya berfungsi untuk baris teks karena karakter NUL tidak didukung kecuali dalam zsh
).
Menggunakan var=value cmd
sintaks memastikan IFS
hanya diatur secara berbeda selama durasi cmd
perintah itu.
Catatan sejarah
The read
builtin diperkenalkan oleh Bourne shell dan sudah membaca kata-kata , bukan baris. Ada beberapa perbedaan penting dengan cangkang POSIX modern.
Shell Bourne read
tidak mendukung -r
opsi (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 c
pada input seperti foo::bar
akan menugaskan bar
untuk $b
, tidak string kosong.
Dalam cangkang Bourne, dengan:
var=value cmd
Jika cmd
built-in (seperti read
ada), var
tetap diatur ke value
setelah cmd
selesai. Itu sangat penting dengan $IFS
karena dalam shell Bourne, $IFS
digunakan untuk membagi segalanya, tidak hanya ekspansi. Juga, jika Anda menghapus karakter spasi dari $IFS
dalam 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 < file
atau exec 3< file; read var <&3
tidak berfungsi), jadi jarang di shell Bourne digunakan read
untuk 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 line
perintah untuk membaca satu baris input (yang dulunya adalah perintah UNIX standar hingga Spesifikasi Single UNIX versi 2 ).
Itu pada dasarnya sama dengan head -n 1
kecuali 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.