Penggandaan dan penambahan bash

18
for k in {0..49};
do
a=$(($((2*$k))+1));
echo $a;
done

Hai, saya perlu ungkapan yang disederhanakan untuk baris ketiga, mungkin yang tidak menggunakan substitusi perintah.

AVS
sumber
@Theophrastus: Seperti yang disarankan berfungsi dengan baik tetapi bagaimana jika saya ingin menggunakan expr bukannya (()).
AVS
Ini bashdan tidak C, jadi hapus semua ;- kecuali Anda menulisnya dalam satu baris.
ott--
Lihat juga: unix.stackexchange.com/q/40786/117549
Jeff Schaller
declare -i a; for k in {0..49}; do a=2*$k+1; echo $a; done
Cyrus
1
Selain itu: $(( ... ))apakah ekspansi aritmatika bukan perintah substitusi.
dave_thompson_085

Jawaban:

27

Menggunakan ekspansi aritmatika:

for (( k = 0; k < 50; ++k )); do
  a=$(( 2*k + 1 ))
  echo "$a"
done

Menggunakan exprutilitas kuno :

for (( k = 0; k < 50; ++k )); do
  a=$( expr 2 '*' "$k" + 1 )
  echo "$a"
done

Menggunakan bc -l( -lsebenarnya tidak diperlukan dalam kasus ini karena tidak ada fungsi matematika yang digunakan):

for (( k = 0; k < 50; ++k )); do
  a=$( bc -l <<<"2*$k + 1" )
  echo "$a"
done

Menggunakan bc -lsebagai proses bersama (ini bertindak seperti semacam layanan perhitungan di latar belakang¹):

coproc bc -l

for (( k = 0; k < 50; ++k )); do
  printf "2*%d + 1\n" "$k" >&${COPROC[1]}
  read -u "${COPROC[0]}" a
  echo "$a"
done

kill "$COPROC_PID"

Yang terakhir terlihat (bisa dibilang) lebih bersih di ksh93:

bc -l |&
bc_pid="$!"

for (( k = 0; k < 50; ++k )); do
  print -p "2*$k + 1"
  read -p a
  print "$a"
done

kill "$bc_pid"

¹ Ini pernah memecahkan masalah bagi saya ketika saya harus memproses sejumlah besar input dalam satu lingkaran. Pemrosesan membutuhkan beberapa perhitungan floating point, tetapi pemijahan bcbeberapa kali dalam loop terbukti sangat lambat. Ya, saya bisa menyelesaikannya dengan banyak cara lain, tetapi saya bosan ...

Kusalananda
sumber
12

Anda dapat menyederhanakan:

a=$(($((2*$k))+1));

untuk:

a=$((2*k+1))
Jeff Schaller
sumber
5

Anda dapat menggunakan letperintah untuk memaksa perhitungan.

let a="2*k+1"

Perhatikan bahwa kita tidak perlu $kdalam struktur ini; sederhana kakan melakukan pekerjaan itu.

Stephen Harris
sumber
4
Itu gagal jika ada file yang dipanggil a=2whateverk+1di direktori saat ini. Lebih buruk lagi, jika ada file yang dipanggil a=2+b[$(reboot)]k+1, yang memanggil rebootperintah. Yang terbaik adalah menggunakan di ((...))sini ( ((a = 2 * k + 1))), atau sintaks POSIX:a=$((2 * k + 1))
Stéphane Chazelas
Kami bisa mengutipnya; let a="2*k+1"untuk menyelesaikannya.
Stephen Harris
2

Perluasan aritmatika yang mungkin Anda butuhkan adalah ini:

a=$(( 1+2*k ))

Bahkan, Anda tidak perlu menggunakan variabel:

for k in {0..49}; do
    echo "$(( 1 + 2*k ))"
done

Atau variabel penghitungan dapat dipindahkan ke for ((…))loop:

for (( k=0;k<50;k++ )); do
    a=$(( 1+2*k ))
    printf '%s\n' "$a"
done

untuk ((...)) loop

Dan, dalam hal itu, ekspansi aritmatika juga dapat dipindahkan ke dalam loop for:

for (( k=0 ; a=1+2*k , k<50 ;  k++)); do
    printf '%s\n' "$a"
done

Atau, untuk mendapatkan semua nilai dalam array:

for (( k=0 ; a[k]=1+2*k , k<49 ;  k++ )); do :; done
printf '%s\n' "${a[@]}"

Tidak ada formula

Tapi mungkin cara terpendek untuk menghindari ekspansi aritmatika adalah dengan menambahkan variabel dua kali:

for (( k=0,a=1 ; k<50 ;  k++,a++,a++ )); do
    printf '%s\n' "$a"
done

Atau, lebih sederhana, cukup gunakan seq:

seq 1 2 100

sumber