GNU/Linux >> Belajar Linux >  >> Linux

Menghitung persentase pembulatan dalam Shell Script tanpa menggunakan bc

Skrip shell yang sesuai dengan POSIX hanya diperlukan untuk mendukung integer aritmatika menggunakan bahasa shell ("hanya diperlukan aritmatika integer panjang yang ditandatangani"), jadi shell murni solusi harus meniru aritmatika titik-mengambang:

item=30
total=70

percent=$(( 100 * item / total + (1000 * item / total % 10 >= 5 ? 1 : 0) ))
  • 100 * item / total menghasilkan terpotong hasil dari bilangan bulat pembagian sebagai persentase.
  • 1000 * item / total % 10 >= 5 ? 1 : 0 menghitung tempat desimal ke-1, dan jika sama dengan atau lebih besar dari 5, tambahkan 1 ke hasil bilangan bulat untuk membulatkannya.
  • Perhatikan bahwa tidak ada perlu mengawali referensi variabel dengan $ di dalam ekspansi aritmatika $((...)) .

Jika - bertentangan dengan premis pertanyaan - penggunaan utilitas eksternal dapat diterima:

  • awk menawarkan sederhana solusi, yang, bagaimanapun, disertai dengan peringatan bahwa ia menggunakan biner presisi ganda yang sebenarnya nilai floating point dan karenanya dapat menghasilkan hasil yang tidak diharapkan dalam desimal representasi - mis., coba printf '%.0f\n' 28.5 , yang menghasilkan 28 daripada 29 yang diharapkan ):
awk -v item=30 -v total=70 'BEGIN { printf "%.0f\n", 100 * item / total }'
  • Perhatikan bagaimana -v digunakan untuk mendefinisikan variabel untuk awk skrip, yang memungkinkan pemisahan bersih antara kutipan tunggal dan karena itu harfiah awk skrip dan nilai apa pun yang diteruskan dari shell .
  • Sebaliknya, meskipun bc adalah utilitas POSIX (dan karena itu dapat diharapkan hadir di sebagian besar platform mirip-Unix) dan melakukan ketepatan sewenang-wenang aritmatika, selalu terpotong hasilnya, sehingga pembulatan harus dilakukan oleh lain kegunaan; printf , namun, meskipun pada prinsipnya utilitas POSIX, tidak diperlukan untuk mendukung penentu format floating-point (seperti yang digunakan di dalam awk di atas), jadi berikut ini mungkin berfungsi atau tidak (dan tidak sebanding dengan masalahnya, mengingat awk yang lebih sederhana solusi, dan mengingat bahwa masalah presisi karena aritmatika floating-point kembali ke gambar):
# !! This MAY work on your platform, but is NOT POSIX-compliant:
# `-l` tells `bc` to set the precision to 20 decimal places, `printf '%.0f\n'`
# then performs the rounding to an integer.
item=20 total=70
printf '%.0f\n' "$(bc -l <<EOF
100 * $item / $total
EOF
)"


Gunakan AWK (tanpa bash-isme):

item=30
total=70
percent=$(awk "BEGIN { pc=100*${item}/${total}; i=int(pc); print (pc-i<0.5)?i:i+1 }")

echo $percent
43

Mengambil 2 * kalkulasi persen asli dan mendapatkan modulo 2 yang memberikan kenaikan untuk pembulatan.

item=30
total=70
percent=$((200*$item/$total % 2 + 100*$item/$total))

echo $percent
43

(diuji dengan bash, ash, dash, dan ksh)

Ini adalah implementasi yang lebih cepat daripada menjalankan koproses AWK:

$ pa() { for i in `seq 0 1000`; do pc=$(awk "BEGIN { pc=100*${item}/${total}; i=int(pc); print (pc-i<0.5)?i:i+1 }"); done; }
$ time pa

real    0m24.686s
user    0m0.376s
sys     0m22.828s

$ pb() { for i in `seq 0 1000`; do pc=$((200*$item/$total % 2 + 100*$item/$total)); done; }
$ time pb

real    0m0.035s
user    0m0.000s
sys     0m0.012s

Linux
  1. Skrip Bash:Menggunakan perintah skrip dari skrip bash untuk mencatat sesi

  2. Apakah mungkin membuat folder secara rekursif menggunakan skrip Shell?

  3. Tambahkan Kolom ke akhir file CSV menggunakan 'awk' dalam skrip BASH

  1. Direktori skrip Shell saat ini?

  2. Skrip shell berfungsi dengan baik tanpa garis shebang? Mengapa?

  3. Dapatkan alamat MAC menggunakan skrip shell

  1. Ulangi variabel $PATH menggunakan skrip Shell

  2. Menggunakan grep vs awk

  3. Shell:apakah mungkin menunda perintah tanpa menggunakan `sleep`?