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.
dc
setiap waktu untuk mempertahankannya.dc
adalah binatang yang berubah-ubah, tetapi mungkin saja merupakan utilitas umum yang tercepat dan paling aneh pada setiap sistem Unix. Ketika dipasangkan dgsed
itu bisa melakukan beberapa hal luar biasa. Saya sudah bermain dengan itu dandd
akhir - akhir ini sehingga saya bisa mengganti keburukan itureadline
. Ini contoh kecil dari beberapa hal yang telah saya lakukan. Melakukanrev
indc
hampir merupakan permainan anak-anak.[string]P91P93P[string]P
. Jadi saya punya sedikit darised
Anda mungkin menemukan berguna:sed 's/[][]/]P93]&[1P[/g;s/[]3][]][[][1[]//g'
yang harus selalu mengganti kotak dengan benar dengan braket tutup string, kemudian aP
, maka nilai ascii desimal kuadrat dan yang lainnyaP
; kemudian[
braket kotak terbuka untuk melanjutkan string. Tidak tahu apakah Anda telah mengacaukandc
kemampuan konversi string / numerik, tetapi - terutama bila dikombinasikan dengan /od
- itu bisa sangat menyenangkan.Jika Anda tahu Anda berurusan dengan dua bilangan bulat
a
danb
, maka ekspansi aritmatika shell sederhana ini menggunakan operator ternary cukup untuk memberikan jumlah numerik:dan angka min:
Misalnya
Berikut ini adalah skrip shell yang menunjukkan ini:
sumber
max=$(( a >= b ? a : b ))
, tetapi hasilnya sepenuhnya sama - jika a dan b sama, maka tidak masalah mana yang dikembalikan. Itukah yang kamu tanyakan?if (( a >= b )); then echo a is greater than or equal to b; fi
- apakah itu yang Anda minta? (perhatikan penggunaan di(( ))
sini alih-alih$(( ))
)sort
danhead
dapat melakukan ini:sumber
O(n log(n))
implementasi maks yang efisienO(n)
. Ini adalah signifikansi kecil kitan=2
, karena pemijahan dua proses jauh lebih besar.numbers="1 4 3 5 7 1 10 21 8";
echo $numbers | tr ' ' "\n" | sort -rn | head -n 1
max=0; for x in $numbers ; do test $x -gt $max && max=$x ; done
Anda bisa mendefinisikan perpustakaan fungsi matematika yang telah ditentukan untuk
bc
dan kemudian menggunakannya di baris perintah.Misalnya, sertakan yang berikut ini dalam file teks seperti
~/MyExtensions.bc
:Sekarang Anda dapat menelepon
bc
dengan:FYI, ada fungsi perpustakaan matematika gratis seperti ini tersedia online.
Dengan menggunakan file itu, Anda dapat dengan mudah menghitung fungsi yang lebih rumit seperti
GCD
:sumber
bc
hanyadc
frontend sampai hari ini, meskipun, bahkan jika GNUbc
tidak lagi seperti itu (tetapi GNUdc
dan GNUbc
berbagi jumlah basis kode yang luar biasa) . Bagaimanapun, ini mungkin jawaban terbaik di sini.bc
, tepat sebelum panggilan fungsi. Tidak diperlukan lagi file kedua :)Terlalu panjang untuk dikomentari:
Meskipun Anda dapat melakukan hal-hal ini misalnya dengan
sort | head
atausort | tail
kombo, tampaknya agak kurang optimal, baik sumber daya maupun penanganan kesalahan. Sejauh menyangkut eksekusi, kombo berarti menelurkan 2 proses hanya untuk memeriksa dua baris. Itu tampaknya sedikit berlebihan.Masalah yang lebih serius adalah, bahwa dalam kebanyakan kasus Anda perlu tahu, bahwa inputnya waras, yang hanya berisi angka. solusi @ glennjackmann dengan cerdik menyelesaikan ini, karena
printf %d
harus muntah pada non-integer. Ini tidak akan bekerja dengan float (kecuali jika Anda mengubah penentu format ke%f
, di mana Anda akan mengalami masalah pembulatan).test $1 -gt $2
akan memberi Anda indikasi apakah perbandingan gagal atau tidak (status keluar dari 2 berarti ada kesalahan selama pengujian. Karena ini biasanya merupakan shell bawaan, tidak ada proses tambahan yang muncul - kita berbicara tentang urutan ratusan kali eksekusi lebih cepat. Hanya bekerja dengan bilangan bulat.Jika Anda perlu membandingkan beberapa angka floating point, opsi menarik mungkin
bc
:akan menjadi setara dengan
test $1 -gt $2
, dan menggunakan di dalam shell:masih hampir 2,5 kali lebih cepat dari
printf | sort | head
(untuk dua angka).Jika Anda dapat mengandalkan ekstensi GNU di
bc
, maka Anda juga dapat menggunakanread()
fungsi untuk membaca angka langsung kebc
sript.sumber
dc -e "${max}sm[z0=?dlm<Mps0lTx]ST[?z0!=Tq]S?[s0lm]SMlTx"
- oh, kecuali yangdc
melakukan semuanya (kecuali gema, meskipun bisa) - membaca stdin dan mencetak salah satu$max
atau nomor input tergantung pada yang lebih kecil. Bagaimanapun, saya tidak terlalu peduli untuk menjelaskannya dan jawaban Anda lebih baik daripada yang akan saya tulis. Tolong, tolong, tolong, tolong.dc
skrip yang dijelaskan akan sangat bagus, RPN tidak terlihat yang sering hari ini.dc
dapat melakukan I / O sendiri itu akan lebih elegan daripada.Untuk mendapatkan nilai lebih besar dari $ a dan $ b gunakan ini:
Tetapi Anda membutuhkan sesuatu di sekitar itu, Anda mungkin tidak bermaksud mengeksekusi angka, jadi untuk menampilkan nilai yang lebih besar dari keduanya gunakan "echo"
Di atas cocok dengan baik ke fungsi shell, misalnya
Untuk menetapkan yang lebih besar dari keduanya ke variabel, gunakan versi modifikasi ini:
atau gunakan fungsi yang didefinisikan:
Variasi fungsi juga memberi Anda kesempatan untuk menambahkan pemeriksaan kesalahan input dengan rapi.
Untuk mengembalikan maksimal dua angka desimal / titik mengambang yang dapat Anda gunakan
awk
EDIT: Menggunakan teknik ini Anda dapat membuat fungsi "batas" yang beroperasi sebaliknya sesuai dengan edit / catatan Anda. Fungsi ini akan mengembalikan yang lebih rendah dari keduanya, misalnya:
Saya suka meletakkan fungsi utilitas ke dalam file terpisah, memanggilnya
myprogram.funcs
dan menggunakannya dalam skrip sebagai berikut:FWIW ini masih melakukan apa yang Anda lakukan, dan versi Anda meskipun lebih verbose, sama efisiennya.
Bentuk yang lebih ringkas tidak benar-benar lebih baik, tetapi mencegah kekacauan dalam skrip Anda. Jika Anda memiliki banyak konstruksi if-then-else-fi yang sederhana, skrip akan cepat mengembang.
Jika Anda ingin menggunakan kembali pemeriksaan untuk jumlah yang lebih besar / lebih kecil beberapa kali dalam satu skrip, masukkan fungsi. Format fungsi membuatnya lebih mudah untuk di-debug dan digunakan kembali dan memungkinkan Anda untuk dengan mudah mengganti bagian skrip itu, misalnya dengan perintah awk untuk dapat menangani angka desimal yang bukan bilangan bulat.
Jika ini adalah kasus penggunaan tunggal, cukup kode itu in-line.
sumber
Anda dapat mendefinisikan suatu fungsi sebagai
Sebut saja
maxnum 54 42
dan gema54
. Anda dapat menambahkan info validasi di dalam fungsi (seperti dua argumen atau angka sebagai argumen) jika Anda mau.sumber
function maxnum {
kemaxnum() {
dan itu akan bekerja untuk lebih banyak kerang.Dari skrip shell, ada cara untuk menggunakan metode statis publik Java apa pun (dan misalnya Math.min () ). Dari bash di Linux:
Ini membutuhkan Java Shell Bridge https://sourceforge.net/projects/jsbridge/
Sangat cepat, karena pemanggilan metode secara internal disalurkan ; tidak diperlukan proses.
sumber
Kebanyakan orang hanya akan melakukan
sort -n input | head -n1
(atau membuntuti), itu cukup baik untuk sebagian besar situasi scripting. Namun, ini agak canggung jika Anda memiliki angka dalam satu baris dan bukan kolom - Anda harus mencetaknya dalam format yang tepat (tr ' ' '\n'
atau yang serupa).Kerang tidak sepenuhnya ideal untuk pemrosesan numerik, tetapi Anda dapat dengan mudah menyalurkan ke beberapa program lain yang lebih baik di dalamnya. Bergantung pada preferensi Anda sendiri, Anda dapat panggilan maksimal
dc
(agak dikaburkan, tetapi jika Anda tahu apa yang Anda lakukan, tidak masalah - lihat jawaban mikeserv), atauawk 'NR==1{max=$1} {if($1>max){max=$1}} END { print max }'
. Atau mungkinperl
ataupython
jika Anda suka. Satu solusi (jika Anda bersedia menginstal dan menggunakan perangkat lunak yang kurang dikenal) adalahised
(terutama jika data Anda berada dalam satu baris: Anda hanya perlu melakukannyaised --l input.dat 'max$1'
).Karena Anda meminta dua nomor, ini semua berlebihan. Ini seharusnya cukup:
sumber
sys.argv
:python2 -c 'import sys; print (max(sys.argv))' "$@"
sort + head
berlebihan tetapipython
tidak menghitung.python
karena rapi.python
fanatik (atau karena tidak memerlukan garpu dan penerjemah raksasa tambahan) . Atau mungkin keduanya.