Saya sudah mencoba menggunakan bash untuk membaca file karakter demi karakter.
Setelah banyak percobaan dan kesalahan, saya menemukan bahwa ini berfungsi:
exec 4<file.txt
declare -i n
while read -r ch <&4;
n=0
while [ ! $n -eq ${#ch} ]
do echo -n "${ch:$n:1}"
(( n++ ))
done
echo ""
done
Yaitu, saya bisa membacanya baris demi baris dan kemudian mengulangi setiap baris char dengan char.
Sebelum melakukan ini, saya telah mencoba:
exec 4<file.txt && while read -r -n1 ch <&4; do; echo -n "$ch"; done
tetapi itu akan melewatkan semua spasi putih di file .
Bisakah Anda jelaskan mengapa? Apakah ada cara untuk membuat strategi kedua (yaitu membaca char by char dengan bash's read) berfungsi?
IFS
apa-apa agar spasi putih bertahan dari pemisahan kata.Jawaban:
Anda perlu menghapus karakter spasi dari
$IFS
parameter untukread
berhenti melompati karakter yang memimpin dan mengekor (dengan-n1
, karakter spasi jika ada yang akan memimpin dan mengekor, jadi dilewati):Tetapi meskipun demikian, bash's
read
akan melewati karakter baris baru, yang dapat Anda atasi:Meskipun Anda dapat menggunakan
IFS= read -d '' -rn1
sebagai gantinya atau bahkan lebih baikIFS= read -N1
(ditambahkan pada 4.1, disalin dariksh93
(ditambahkan dalamo
)) yang merupakan perintah untuk membaca satu karakter.Perhatikan bahwa bash
read
tidak dapat mengatasi karakter NUL. Dan ksh93 memiliki masalah yang sama dengan bash.Dengan zsh:
(zsh dapat mengatasi karakter NUL).
Perhatikan bahwa mereka
read -k/n/N
membaca sejumlah karakter , bukan byte . Jadi untuk karakter multibyte, mereka mungkin harus membaca beberapa byte hingga karakter penuh dibaca. Jika input berisi karakter yang tidak valid, Anda mungkin berakhir dengan variabel yang berisi urutan byte yang tidak membentuk karakter yang valid dan yang shell akhirnya menghitung sebagai beberapa karakter . Misalnya di lokal UTF-8:Itu
\375
akan memperkenalkan karakter UTF-8 6-byte. Namun, yang ke-6 (A
) di atas tidak valid untuk karakter UTF-8. Anda masih berakhir dengan\375\200\200\200\200A
di$a
, yangbash
dihitung sebagai 6 karakter meskipun 5 yang pertama tidak benar-benar karakter, hanya 5 byte yang tidak membentuk bagian dari karakter apa pun.sumber
read -rN1
bukan memecahkan masalah baris baru dan dengan demikian menghilangkan perlu memberikan baris baru sebagai default saat mencetak$a
.read -n1
(char by char) membutuhkan waktu 4 menit 51 detik dan memanaskan laptop hingga 90 derajat. Menggunakanread -r
(baris demi baris) membutuhkan 1,3 detik dan laptop tetap pada 54 derajat dengan kipas ganda diam.Ini adalah contoh sederhana menggunakan
cut
,for
lingkaran &wc
:CIUMAN bukan?
sumber
bash
solusi:file="$(</etc/passwd)"; bytes="${#file}"; for ((i=0;i<bytes;i++)); do echo "${file:i:1}"; done
?bash
“Ini terlalu besar dan terlalu lambat.” menurut bagian BUGS halaman manualnya. Namun demikian, masih lebih cepat untuk mengiris string dalam memori daripada membaca file lagi dan lagi untuk setiap karakter. Setidaknya di mesin saya: pastebin.com/zH5trQQs