Fungsi cangkang. Ini akan berfungsi di semua shell yang mendukung <<<
di sini-string, termasuk zsh dan bash.
xyz() {
while read line
do
printf "%s " "$line"
"[email protected]" <<<"$line"
done
}
$ (echo "foo"; echo "bar") | xyz rev
foo oof
bar rab
Akan ada banyak masalah dalam banyak kasus karena cara kerja stdio buffering. Solusi untuk linux mungkin menggunakan stdbuf
program dan jalankan perintah dengan coproc, sehingga Anda dapat secara eksplisit mengontrol interleaving keluaran.
Berikut ini mengasumsikan bahwa perintah akan menampilkan satu baris setelah setiap baris masukan.
#!/bin/bash
coproc stdbuf -i0 -o0 "[email protected]"
IFS=
while read -r in ; do
printf "%s " "$in"
printf "%s\n" "$in" >&${COPROC[1]}
read -r out <&${COPROC[0]}
printf "%s\n" "$out"
done
Jika diperlukan solusi yang lebih umum karena OP hanya memerlukan setiap baris masukan ke program untuk pada akhirnya output satu baris daripada segera, maka diperlukan pendekatan yang lebih rumit. Buat loop peristiwa menggunakan read -t 0
untuk mencoba dan membaca dari stdin dan proses bersama, jika Anda memiliki "nomor baris" yang sama untuk keduanya, maka hasilkan, jika tidak, simpan baris tersebut. Untuk menghindari penggunaan 100% cpu jika di putaran mana pun loop acara tidak ada yang siap, maka perkenalkan penundaan kecil sebelum menjalankan loop acara lagi. Ada komplikasi tambahan jika proses mengeluarkan sebagian baris, ini perlu di-buffer.
Jika solusi yang lebih umum ini diperlukan, saya akan menulis ini menggunakan ekspektasi karena sudah memiliki dukungan yang baik untuk menangani pencocokan pola pada beberapa input stream. Namun ini bukan solusi bash/zsh.
Dalam kasus khusus ini, saya akan menggunakan perl
:
printf '%s\n' foo bar | perl -Mopen=locale -lpe '$_ .= " " . reverse$_'
foo oof
bar rab
Yang dapat Anda kembangkan untuk juga berfungsi dengan kluster grafem:
$ printf '%s\n' $'complique\u301' |
perl -Mopen=locale -lpe '$_ .= " " . join "", reverse/\X/g'
compliqué éuqilpmoc
Atau zsh
:
while IFS= read -r line; do
print -r -- $line ${(j::)${(s::Oa)line}}
done
Meskipun saya akan menghindari penggunaan while read
loop untuk memproses teks, bahkan di zsh
(meskipun dalam kasus khusus ini, tidak terlalu buruk karena hanya perintah bawaan yang digunakan).
Dalam kasus umum, menggunakan file temp mungkin merupakan pendekatan terbaik. Dengan zsh
, Anda dapat melakukannya dengan:
(){paste -d ' ' $1 <(rev <$1)} =(print -l foo bar)
(di mana =(...)
menangani pembuatan dan pembersihan file temp).
Menggantinya dengan pipa dan beberapa bentuk tee
ing adalah resep untuk kebuntuan dalam kasus umum. Lihat pertanyaan serupa ini untuk beberapa pendekatan dan detail tentang situasi kebuntuan:
- Pisahkan input untuk perintah yang berbeda dan gabungkan hasilnya
- tee + cat:gunakan keluaran beberapa kali lalu gabungkan hasil