Anda dapat membandingkan hanya dua angka dengan dc
seperti:
dc -e "[$1]sM $2d $1<Mp"
... di mana "$1"
nilai maksimum Anda dan "$2"
merupakan angka yang akan Anda cetak jika lebih rendah dari itu "$1"
. Itu juga membutuhkan GNU dc
- tetapi Anda dapat melakukan hal yang sama dengan mudah seperti:
dc <<MAX
[$1]sM $2d $1<Mp
MAX
Dalam kedua kasus di atas Anda dapat mengatur presisi ke sesuatu selain 0 (default) seperti ${desired_precision}k
. Untuk keduanya, Anda juga harus memastikan bahwa kedua nilai tersebut merupakan angka pasti karena dc
dapat membuat system()
panggilan dengan !
operator.
Dengan skrip kecil berikut (dan selanjutnya) Anda harus memverifikasi input juga - suka grep -v \!|dc
atau sesuatu untuk menangani input sewenang - wenang. Anda juga harus tahu bahwa dc
menafsirkan angka negatif dengan _
awalan daripada -
awalan - karena yang terakhir adalah operator pengurangan.
Selain itu, dengan skrip ini dc
akan terbaca \n
nomor ewline terpisah berurutan sebanyak yang Anda mau berikan, dan cetak untuk setiap $max
nilai atau input Anda, tergantung mana yang lebih rendah dari wo:
dc -e "${max}sm
[ z 0=? d lm<M p s0 lTx ]ST
[ ? z 0!=T q ]S?
[ s0 lm ]SM lTx"
Jadi ... masing-masing [
persegi kurung ]
hamparan adalah dc
string yang objek yang S
aved masing-masing untuk array yang masing-masing - salah satu dari T
, ?
atau M
. Selain beberapa hal lain yang dc
mungkin dilakukan dengan sebuah string , ia juga dapat menjadikannya x
sebagai makro. Jika Anda mengaturnya dengan benar, dc
skrip kecil yang berfungsi penuh dirakit cukup sederhana.
dc
bekerja pada tumpukan . Semua objek input ditumpuk masing-masing pada yang terakhir - setiap objek input baru mendorong objek teratas terakhir dan semua objek di bawahnya di atas tumpukan dengan satu saat ditambahkan. Sebagian besar referensi ke objek adalah ke nilai tumpukan teratas, dan sebagian besar referensi muncul di atas tumpukan (yang menarik semua objek di bawahnya satu per satu) .
Selain tumpukan utama, ada juga (setidaknya) 256 array dan masing-masing elemen array memiliki tumpukan sendiri. Saya tidak banyak menggunakan itu di sini. Saya hanya menyimpan string seperti yang disebutkan sehingga saya dapat menggunakannya l
ketika diinginkan dan membuat x
mereka kondisional, dan saya s
merobek $max
nilai di bagian atas m
array.
Bagaimanapun, sedikit ini dc
tidak, sebagian besar, apa yang dilakukan oleh shell-script Anda. Itu memang menggunakan opsi GNU-isme -e
- seperti dc
umumnya mengambil parameternya dari standard-in - tetapi Anda bisa melakukan hal yang sama seperti:
echo "$script" | cat - /dev/tty | dc
... jika $script
tampak seperti bit di atas.
Ini berfungsi seperti:
lTx
- Ini l
oads dan e x
ecutes makro disimpan di bagian atas T
(untuk tes, saya kira - Saya biasanya mengambil nama-nama sewenang-wenang) .
z 0=?
- T
est kemudian menguji kedalaman tumpukan dengan z
dan, jika tumpukan kosong (baca: menampung 0 objek) ia memanggil ?
makro.
? z0!=T q
- ?
Makro dinamai untuk ?
dc
perintah builtin yang membaca baris input dari stdin, tapi saya juga menambahkan z
tes kedalaman tumpukan lain untuk itu, sehingga dapat cocok q
dengan seluruh program kecil jika menarik garis kosong atau menekan EOF. Tetapi jika !
tidak dan malah berhasil mengisi stack, ia memanggil T
est lagi.
d lm<M
- T
est kemudian akan d
menggandakan bagian atas tumpukan dan membandingkannya dengan $max
(seperti yang disimpan di m
) . Jika m
nilainya lebih rendah, dc
panggil M
makro.
s0 lm
- M
Hanya muncul bagian atas tumpukan dan membuangnya ke skalar dummy 0
- hanya cara murah untuk muncul tumpukan. Hal ini juga l
oads m
lagi sebelum kembali ke T
est.
p
- Ini berarti bahwa jika m
kurang dari puncak tumpukan saat ini, maka m
ganti itu (bagian d
atasnya, bagaimanapun) dan di sini di- p
bengkokkan, yang lain tidak dan apa pun input yang di- p
bengkokkan sebagai gantinya.
s0
- Setelah itu (karena p
tidak memunculkan tumpukan) kami membuang bagian atas tumpukan 0
lagi, dan kemudian ...
lTx
- rekursif l
oad T
est sekali lagi maka e x
ecute lagi.
Jadi, Anda dapat menjalankan potongan kecil ini dan mengetik nomor secara interaktif di terminal Anda dan dc
akan mencetak kembali pada Anda nomor yang Anda masukkan atau nilai $max
jika nomor yang Anda ketikkan lebih besar. Itu juga akan menerima file apa pun (seperti pipa) sebagai input standar. Ini akan melanjutkan loop baca / bandingkan / cetak sampai bertemu dengan garis kosong atau EOF.
Beberapa catatan tentang ini - saya menulis ini hanya untuk meniru perilaku dalam fungsi shell Anda, sehingga hanya menangani satu angka per baris dengan kuat. dc
namun, dapat menangani sebanyak mungkin angka yang dipisahkan spasi per baris seperti yang Anda inginkan. Namun , karena tumpukannya, angka terakhir pada sebuah garis akhirnya menjadi yang pertama beroperasi, dan, seperti yang tertulis, dc
akan mencetak hasilnya secara terbalik jika Anda mencetak / mengetik lebih dari satu angka per baris di dalamnya. Cara yang tepat untuk mengatasinya adalah dengan menyimpan sebuah baris dalam sebuah array, kemudian mengerjakannya.
Seperti ini:
dc -e "${max}sm
[ d lm<M la 1+ d sa :a z0!=A ]SA
[ la d ;ap s0 1- d sa 0!=P ]SP
[ ? z 0=q lAx lPx l?x ]S?
[q]Sq [ s0 lm ]SM 0sa l?x"
Tapi ... Saya tidak tahu apakah saya ingin menjelaskannya secara mendalam. Cukuplah untuk mengatakan bahwa ketika dc
dibaca di setiap nilai pada stack ia menyimpan nilai atau $max
nilainya dalam array yang diindeks, dan, begitu ia mendeteksi stack sekali lagi kosong, ia kemudian mencetak setiap objek yang diindeks sebelum mencoba membaca yang lain jalur input.
Jadi, sementara skrip pertama tidak ...
10 15 20 25 30 ##my input line
20
20
20
15
10 ##see what I mean?
Yang kedua tidak:
10 15 20 25 30 ##my input line
10 ##that's better
15
20
20 ##$max is 20 for both examples
20
Anda dapat menangani float dengan presisi sewenang-wenang jika Anda pertama kali mengaturnya dengan k
perintah. Dan Anda dapat mengubah i
nput atau radisi o
utput secara independen - yang kadang-kadang bisa berguna karena alasan yang mungkin tidak Anda harapkan. Sebagai contoh:
echo 100000o 10p|dc
00010
... yang pertama mengatur dc
output radix ke 100000 kemudian mencetak 10.