Phép nhân và phép cộng Bash


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

Xin chào, tôi cần một biểu thức đơn giản hóa cho dòng thứ ba, có thể là biểu thức không sử dụng thay thế lệnh.


@Theophrastus: Theo đề xuất, nó hoạt động tốt nhưng nếu tôi muốn sử dụng expr thay vì (()).
AVS

Đây là bashvà không C, vì vậy hãy loại bỏ tất cả ;- trừ khi bạn viết nó trong một dòng số ít.
ott--


declare -i a; for k in {0..49}; do a=2*$k+1; echo $a; done
Cyrus

1
Ngoài ra: $(( ... ))là mở rộng số học không thay thế lệnh.
dave_thndry_085

Câu trả lời:


27

Sử dụng mở rộng số học:

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

Sử dụng exprtiện ích cổ :

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

Sử dụng bc -l( -lkhông thực sự cần thiết trong trường hợp này vì không có chức năng toán học nào được sử dụng):

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

Sử dụng bc -lnhư một đồng xử lý (nó hoạt động như một loại dịch vụ tính toán trong nền¹):

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"

Cái cuối cùng có vẻ sạch hơn (được cho là) ​​trong 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"

Điều này đã giải quyết một vấn đề cho tôi một lần khi tôi cần xử lý một lượng lớn đầu vào trong một vòng lặp. Việc xử lý yêu cầu một số tính toán dấu phẩy động, nhưng sinh sản bcmột vài lần trong vòng lặp tỏ ra cực kỳ chậm. Phải, tôi có thể giải quyết nó bằng nhiều cách khác, nhưng tôi đã chán ...



5

Bạn có thể sử dụng letlệnh để buộc tính toán.

let a="2*k+1"

Lưu ý rằng chúng ta không cần $ktrong cấu trúc này; một đơn giản ksẽ làm công việc.


4
Điều đó không thành công nếu có một tệp được gọi a=2whateverk+1trong thư mục hiện tại. Tệ hơn, nếu có một tệp được gọi a=2+b[$(reboot)]k+1, nó sẽ gọi rebootlệnh. Tốt nhất là sử dụng ((...))ở đây ( ((a = 2 * k + 1))) hoặc cú pháp POSIX:a=$((2 * k + 1))
Stéphane Chazelas

Chúng tôi có thể trích dẫn nó; let a="2*k+1"để giải quyết điều đó.
Stephen Harris

2

Việc mở rộng số học mà bạn có thể cần là:

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

Thực tế, bạn không cần sử dụng biến:

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

Hoặc biến đếm có thể được chuyển sang một for ((…))vòng lặp:

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

vòng lặp for (())

Và, trong trường hợp đó, việc mở rộng số học cũng có thể được chuyển sang bên trong vòng lặp for:

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

Hoặc, để có được tất cả các giá trị trong một mảng:

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

Không có công thức

Nhưng có lẽ cách ngắn nhất để tránh mọi sự mở rộng số học là tăng một biến hai lần:

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

Hoặc, thậm chí đơn giản hơn, chỉ cần sử dụng seq:

seq 1 2 100
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.