Jak mogę dokonać podziału za pomocą zmiennych w powłoce Linuksa?

136

Kiedy uruchamiam polecenia w mojej powłoce, jak poniżej, zwraca expr: non-integer argumentbłąd. Czy ktoś może mi to wyjaśnić?

$ x=20
$ y=5
$ expr x / y 
expr: non-integer argument
Judking
źródło
4
@ShivanRaptor Chociaż można by argumentować, że jest to kwestia RTFM, z pewnością jest to poprawne pytanie dotyczące programowania powłoki. Jest to również rozsądne pytanie dla kogoś pochodzącego z języków, które nie wymagają dereferencji (np. Ruby lub JavaScript). Powinien pozostać otwarty.
Todd A. Jacobs
6
@ShivanRaptor Nie, to jest temat tutaj. Chodzi o programowanie w Bash. Unix / Linux służy głównie do korzystania z systemu, a nie do programowania. Otóż, skrypty powłoki wykraczają poza granice między programowaniem a używaniem systemu, więc może to być tematem w obu witrynach. Gdyby pojawiło się pytanie „jak skonfigurować sieć”, z pewnością pasowałoby to w systemie Unix / Linux. Gdyby chodziło o interaktywne skróty klawiszowe w Bash, to też by tu pasowało. Ale pytanie o skrypty powłoki jest zdecydowanie tematem zarówno tutaj, jak i tam.
Brian Campbell
Zobacz moją odpowiedź tutaj, która ilustruje odejmowanie i dzielenie zmiennych $ BASH, używając wywołania Pythona z powłoki (aby przekonwertować int na float ...): stackoverflow.com/questions/8385627/…
Victoria Stuart

Odpowiedzi:

195

Te zmienne są zmiennymi powłoki. Aby rozwinąć je jako parametry do innego programu ( tj. expr ), Musisz użyć $przedrostka:

expr $x / $y

Narzekał, ponieważ sądził, że próbujesz operować na znakach alfabetycznych ( tj. Nie-całkowitych)

Jeśli używasz powłoki Bash, możesz osiągnąć ten sam wynik, używając składni wyrażenia:

echo $((x / y))

Lub:

z=$((x / y))
echo $z
niełuskany
źródło
1
Możesz dowiedzieć się wiele, czytając stronę podręcznika systemowego bash. Wpisz man bashpo znaku zachęty ( qaby wyjść)
niełuskany
62
Gdzieś na tej stronie należy zauważyć, że większość (jeśli nie wszystkie) powłok GNU / Linux wykonuje tylko operacje na liczbach całkowitych .
Skippy le Grand Gourou
35

Myślę, że wspomniano już o tym w innych wątkach:

calc(){ awk "BEGIN { print "$*" }"; }

możesz po prostu wpisać:

calc 7.5/3.2
  2.34375

W Twoim przypadku będzie to:

x=20; y=3;
calc $x/$y

lub jeśli wolisz, dodaj to jako oddzielny skrypt i udostępnij w $ PATH, aby zawsze mieć go w swojej lokalnej powłoce:

#!/bin/bash
calc(){ awk "BEGIN { print $* }"; }
zielonys
źródło
4
Możesz również użyćecho '1 / 3' | bc -l
Eugene
19

Dlaczego nie skorzystać z let; Uważam to za dużo łatwiejsze. Oto przykład, który może okazać się przydatny:

start=`date +%s`
# ... do something that takes a while ...
sleep 71

end=`date +%s`
let deltatime=end-start
let hours=deltatime/3600
let minutes=(deltatime/60)%60
let seconds=deltatime%60
printf "Time spent: %d:%02d:%02d\n" $hours $minutes $seconds

Kolejny prosty przykład - oblicz liczbę dni od 1970 roku:

let days=$(date +%s)/86400
Mike Behr
źródło
15

Odwoływanie się do zmiennych Bash wymaga rozszerzenia parametrów

Domyślną powłoką w większości dystrybucji Linuksa jest Bash. W Bash zmienne muszą używać przedrostka w postaci znaku dolara do rozwijania parametrów . Na przykład:

x=20
y=5
expr $x / $y

Oczywiście Bash ma również operatory arytmetyczne i specjalną składnię interpretacji arytmetycznej , więc nie ma potrzeby wywoływania pliku binarnego wyrażenia jako oddzielnego procesu. Możesz pozwolić powłoce wykonać całą pracę w ten sposób:

x=20; y=5
echo $((x / y))
Todd A. Jacobs
źródło
Zobacz Arithmetic Expansion and Shell Arithmetic w podręczniku Bash Reference Manual dla wszystkich krwawych szczegółów.
Todd A. Jacobs
1
Nie ma to nic wspólnego z dereferencją, ale interpolacją i exprjest odradzane w 2013 roku.
Gilles Quenot
@sputnick Jesteś wyraźnie zdezorientowany. Zachęcamy do skorzystania ze słownika. Zobacz wyłuskiwanie i interpolacja .
Todd A. Jacobs
1
Lepsze słowo to rozszerzenie , ale nie wyłuskiwanie . dereferencja jest używana, gdy używamy wskaźników , tak nie jest w tym przypadku, to tylko proste zmienne.
Gilles Quenot
1
@Prashant: tldp nie jest dobrym odniesieniem w świecie bash.
Gilles Quenot
1

Załóżmy, że

x=50
y=5

następnie

z=$((x/y))

to będzie działać poprawnie. Ale jeśli chcesz użyć operatora / w przypadku instrukcji, nie może tego rozwiązać. Wprowadź kod tutaj W takim przypadku użyj prostych łańcuchów, takich jak div, divide lub coś innego. Zobacz kod

Pooja Rajput
źródło
To jest źle. /działa dobrze jako etykieta typu shell-case. To, co nie działa, to *mnożenie bez cytowania, co może być tym, co faktycznie zrobiłeś; to powoduje, że skutecznie zastępuje wszystkie następujące elementy w przypadku, które w twoim przykładzie to „devide” i „modulo”
dave_thompson_085
0

Aby uzyskać liczby po przecinku, możesz to zrobić: -

read num1 num2
div=`echo $num1 / $num2 |bc -l`
echo $div
Shayan Chatterjee
źródło