Trừ hai biến trong Bash


220

Tôi có đoạn script dưới đây để trừ số lượng tệp giữa hai thư mục nhưng COUNT=biểu thức không hoạt động. Cú pháp đúng là gì?

#!/usr/bin/env bash

FIRSTV=`ls -1 | wc -l`
cd ..
SECONDV=`ls -1 | wc -l`
COUNT=expr $FIRSTV-$SECONDV  ## -> gives 'command not found' error
echo $COUNT

Câu trả lời:


224

Bạn chỉ cần thêm một chút khoảng trắng xung quanh dấu trừ và backticks:

COUNT=`expr $FIRSTV - $SECONDV`

Hãy nhận biết tình trạng thoát:

Trạng thái thoát là 0 nếu EXPRESSION không null hoặc 0, 1 nếu EXPRESSION là null hoặc 0 .

Hãy ghi nhớ điều này khi sử dụng biểu thức trong tập lệnh bash kết hợp với tập -e sẽ thoát ngay lập tức nếu lệnh thoát với trạng thái khác không.


2
Câu trả lời này cũng hoạt động trong shvỏ posix . Đối với tính di động, bạn có thể muốn sử dụng câu trả lời này.
dinkelk

Điều đáng chú ý là theo Shellcheck, expr là một mật mã do nó bị lỗi thời và khó sử dụng: github.com/koalaman/shellcheck/wiki/SC2003
John Hamelink

369

Hãy thử cú pháp Bash này thay vì cố gắng sử dụng một chương trình bên ngoài expr:

count=$((FIRSTV-SECONDV))

BTW, cú pháp sử dụng đúng exprlà:

count=$(expr $FIRSTV - $SECONDV)

Nhưng hãy nhớ rằng việc sử dụng exprsẽ chậm hơn cú pháp Bash nội bộ mà tôi đã cung cấp ở trên.


4
Hình thức này là cường độ nhanh hơn so với sử dụng chương trình bên ngoài expr.
NSG

Điều này hoạt động mà không có backticks, nhưng tôi có thể biết tại sao? +1 cho câu trả lời.r
Amal Murali

2
Cảm ơn. Backtick là cú pháp shell cũ. BASH hỗ trợ $(command)cú pháp mới để thay thế lệnh. Ngoài ra, vì BASH hỗ trợ các hoạt động số học trong $(( ... ))việc tốt hơn là không sử dụng tiện ích bên ngoàiexpr
anubhava

1
Tôi không bao giờ mới bạn có thể tham chiếu các biến mà không có "$", rất thú vị. Điều này hoạt động trên Ubuntu 12,14 chỉ FYI.
MadHatter

1
@ AlikElzin-kilaka: Trong bash $(( ... ))được sử dụng để đánh giá các biểu thức số học.
anubhava

30

Bạn có thể dùng:

((count = FIRSTV - SECONDV))

để tránh gọi một quy trình riêng biệt, theo bảng điểm sau:

pax:~$ FIRSTV=7
pax:~$ SECONDV=2
pax:~$ ((count = FIRSTV - SECONDV))
pax:~$ echo $count
5

12

Không gian trắng là quan trọng, exprhy vọng toán hạng và toán tử của nó là các đối số riêng biệt. Bạn cũng phải nắm bắt đầu ra. Như thế này:

COUNT=$(expr $FIRSTV - $SECONDV)

nhưng nó phổ biến hơn để sử dụng mở rộng số học dựng sẵn:

COUNT=$((FIRSTV - SECONDV))

12

Đây là cách tôi luôn làm toán ở Bash:

count=$(echo "$FIRSTV - $SECONDV"|bc)
echo $count

5
Điều đó chỉ cần thiết nếu bạn đang xử lý các số dấu phẩy động.
glenn jackman

2
Tôi nhận ra điều đó, nhưng tôi thà tạo thói quen bắt những trường hợp đó bằng |bclệnh loại hơn là bỏ lỡ nó một hoặc hai lần. Nét khác nhau cho những người khác nhau như họ nói.
Pureferret

5

Đối với số học số nguyên đơn giản, bạn cũng có thể sử dụng lệnh let dựng sẵn .

 ONE=1
 TWO=2
 let "THREE = $ONE + $TWO"
 echo $THREE
    3

Để biết thêm thông tin về let, xem tại đây .


@ other.anon.coward Liên kết của bạn tốt hơn của tôi +1. (... Và liên kết ăn cắp)
Shawn Chin

Có rất nhiều rắc rối trong việc này làm việc. Cuối cùng điều này đã làm việc -let "sanity_check_duration=sanity_check_duration_end_time_delay_sec - sanity_check_duration_start_time_delay_sec" (loại bỏ ký hiệu đô la khỏi các biến)
Sandeepan Nath

2

Ngoài ra, với 3 phương pháp được đề xuất, bạn có thể thử letthực hiện các phép toán số học trên các biến như sau:

let COUNT=$FIRSTV-$SECONDV

hoặc là

let COUNT=FIRSTV-SECONDV


0

Sử dụng Python:

#!/bin/bash
# home/victoria/test.sh

START=$(date +"%s")                                     ## seconds since Epoch
for i in $(seq 1 10)
do
  sleep 1.5
  END=$(date +"%s")                                     ## integer
  TIME=$((END - START))                                 ## integer
  AVG_TIME=$(python -c "print(float($TIME/$i))")        ## int to float
  printf 'i: %i | elapsed time: %0.1f sec | avg. time: %0.3f\n' $i $TIME $AVG_TIME
  ((i++))                                               ## increment $i
done

Đầu ra

$ ./test.sh 
i: 1 | elapsed time: 1.0 sec | avg. time: 1.000
i: 2 | elapsed time: 3.0 sec | avg. time: 1.500
i: 3 | elapsed time: 5.0 sec | avg. time: 1.667
i: 4 | elapsed time: 6.0 sec | avg. time: 1.500
i: 5 | elapsed time: 8.0 sec | avg. time: 1.600
i: 6 | elapsed time: 9.0 sec | avg. time: 1.500
i: 7 | elapsed time: 11.0 sec | avg. time: 1.571
i: 8 | elapsed time: 12.0 sec | avg. time: 1.500
i: 9 | elapsed time: 14.0 sec | avg. time: 1.556
i: 10 | elapsed time: 15.0 sec | avg. time: 1.500
$
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.