Yang perlu dijelaskan adalah bahwa perintah itu tampaknya berfungsi, bukan kode keluarnya
'\n'
adalah dua karakter: garis miring terbalik \dan satu huruf n. Apa yang Anda pikir Anda butuhkan adalah $'\n'
, yang merupakan linefeed (tetapi itu juga tidak benar, lihat di bawah).
The -d
opsi melakukan hal ini:
-d delim continue until the first character of DELIM is read, rather
than newline
Jadi tanpa opsi itu, read
akan membaca hingga baris baru, membagi garis menjadi kata-kata menggunakan karakter $IFS
sebagai pemisah, dan memasukkan kata-kata ke dalam array. Jika Anda menentukan -d $'\n'
, mengatur pembatas garis ke baris baru, itu akan melakukan hal yang persis sama . Pengaturan -d '\n'
berarti bahwa ia akan membaca hingga backslash pertama (tetapi, sekali lagi, lihat di bawah), yang merupakan karakter pertama di delim
. Karena tidak ada garis miring terbalik di file Anda, maka read
akan berakhir pada akhir file, dan:
Exit Status:
The return code is zero, unless end-of-file is encountered, read times out,
or an invalid file descriptor is supplied as the argument to -u.
Jadi itu sebabnya kode keluar adalah 1.
Dari fakta bahwa Anda percaya bahwa perintah itu berfungsi, kita dapat menyimpulkan bahwa tidak ada spasi di file, sehingga read
, setelah membaca seluruh file dengan harapan sia-sia menemukan backslash, akan membaginya dengan spasi putih (nilai default dari $IFS
), termasuk baris baru. Jadi setiap baris (atau setiap kata, jika satu baris berisi lebih dari satu kata) disimpan ke dalam array.
Kasus misterius backslash purloined
Sekarang, bagaimana saya tahu file tersebut tidak mengandung garis miring terbalik? Karena Anda tidak memasok -r
bendera ke read
:
-r do not allow backslashes to escape any characters
Jadi, jika Anda memiliki garis miring terbalik di file, mereka akan dilucuti, kecuali jika Anda memiliki dua dari mereka berturut-turut. Dan, tentu saja, ada bukti yang read
memiliki kode keluar 1, yang menunjukkan bahwa itu tidak menemukan backslash, jadi tidak ada dua dari mereka berturut-turut.
Takeaways
Bash tidak akan menjadi bash jika tidak ada gotchas bersembunyi di balik setiap perintah, dan read
tidak terkecuali. Berikut adalah pasangannya:
Kecuali Anda tentukan -r
, read
akan menafsirkan urutan melarikan diri backslash. Kecuali jika memang itu yang Anda inginkan (yang memang sesekali, tetapi hanya sesekali), Anda harus ingat untuk menentukan -r
agar karakter tidak hilang dalam kasus yang jarang ada backslash pada input.
Fakta yang read
mengembalikan kode keluar 1 tidak berarti gagal. Mungkin berhasil, kecuali untuk menemukan terminator garis. Jadi hati-hati dengan loop seperti ini: while read -r LINE; do something with LINE; done
karena akan gagal do something
dengan baris terakhir dalam kasus yang jarang terjadi bahwa baris terakhir tidak memiliki baris baru di akhir.
read -r LINE
mempertahankan garis miring terbalik, tetapi itu tidak mempertahankan spasi spasial memimpin atau tertinggal.
while read
". Kalau tidak, jawaban yang fantastis.while read
selama Anda tidak memiliki apa pun di dalam loop. Kalau tidak, itu bug yang menunggu untuk menggigit Anda - dan percayalah, saya sudah digigit.read
.mapfile
cukup keren. Untuk hack cepat & kotor, saya akan menggunakan loop terlarang sementara, tapi saya sudah berhenti memasukkannya ke dalam skrip produksi. YMMV dan saya melunakkan peringatan dalam jawabannya.Itu adalah perilaku yang diharapkan:
sumber