Skrypty Bash: 365-024 = 345?

2

Próbuję zbudować kilka skryptów dla początkujących za pomocą bash. Chcę dowiedzieć się, ile dni pozostało od dzisiaj do końca roku, korzystając z programu daty.

Więc używam zmiennej, bieżąca data = $ (data +% j), aby uzyskać numer dnia, który mamy teraz.

Jeśli powtórzę $ bieżąca data , otrzymam wynik 024 , jak zwykle się spodziewam, ponieważ mamy 24 stycznia.

Więc 365-024 czasy w lewo. I oto moje zapytanie. Robiąc obliczenia, powiedzmy calc 365-024 Otrzymuję wartość 345 zamiast 341 .

Co jest nie tak? Ma to coś wspólnego z zero na froncie ( 0 24), prawda?

Skemelio
źródło
Możesz wymusić ocenę dziesiętną w bash, poprzedzając ją 10#np $((365-10#$current_date)). Aby uzyskać dalszą dyskusję, zobacz to pytanie Przepełnienie stosu Skrypt Bash, nielegalny numer: 08
steeldriver

Odpowiedzi:

2

Co jest nie tak? Ma to coś wspólnego z zero na froncie (024), prawda?

Tak. Znak wiodący 0oznacza, że ​​liczba jest interpretowana jako liczba ósemkowa (podstawa 8).

  • Oktal 024 == Dziesiętny 20.

Aby zinterpretować liczbę jako liczbę dziesiętną, użyj:

$ echo $((024))
20

Aby uzyskać więcej informacji, zobacz jak wyłączyć interpretację liczb ósemkowych bash? (należy interpretować jako dziesiętny), który konkretnie rozwiązuje ten problem podczas wykonywania obliczeń za pomocą date.


Stałe numeryczne

Skrypt powłoki interpretuje liczbę jako dziesiętną (podstawa 10), chyba że liczba ta ma specjalny prefiks lub notację.

  • Liczba poprzedzona cyfrą 0 jest ósemkowa (podstawa 8).
  • Liczba poprzedzona przez 0x to liczba szesnastkowa (podstawa 16).
  • Liczba z osadzonym # jest obliczana jako PODSTAWOWA NUMER (z ograniczeniem zasięgu i notacji).

Reprezentacja stałych numerycznych

#!/bin/bash
# numbers.sh: Representation of numbers in different bases.

# Decimal: the default
let "dec = 32"
echo "decimal number = $dec"             # 32
# Nothing out of the ordinary here.


# Octal: numbers preceded by '0' (zero)
let "oct = 032"
echo "octal number = $oct"               # 26
# Expresses result in decimal.
# --------- ------ -- -------


# Hexadecimal: numbers preceded by '0x' or '0X'
let "hex = 0x32"
echo "hexadecimal number = $hex"         # 50

echo $((0x9abc))                         # 39612
#     ^^      ^^   double-parentheses arithmetic expansion/evaluation
# Expresses result in decimal.



# Other bases: BASE#NUMBER
# BASE between 2 and 64.
# NUMBER must use symbols within the BASE range, see below.


let "bin = 2#111100111001101"
echo "binary number = $bin"              # 31181

let "b32 = 32#77"
echo "base-32 number = $b32"             # 231

let "b64 = 64#@_"
echo "base-64 number = $b64"             # 4031
# This notation only works for a limited range (2 - 64) of ASCII characters.
# 10 digits + 26 lowercase characters + 26 uppercase characters + @ + _


echo

echo $((36#zz)) $((2#10101010)) $((16#AF16)) $((53#1aA))
                                         # 1295 170 44822 3375


#  Important note:
#  --------------
#  Using a digit out of range of the specified base notation
#+ gives an error message.

let "bad_oct = 081"
# (Partial) error message output:
#  bad_oct = 081: value too great for base (error token is "081")
#              Octal numbers use only digits in the range 0 - 7.

exit $?   # Exit value = 1 (error)

# Thanks, Rich Bartell and Stephane Chazelas, for clarification.

Source Advanced Bash-Scripting Guide - Stałe numeryczne

DavidPostill
źródło
1

Wpisywanie liczb z wiodącym 0 jest konwencją dla notacji ósemkowej, podobnie jak przedrostek 0x oznacza szesnastkę. Więc 024 jest interpretowane jak 2 * 8 + 4 == 20. Zobacz wynik polecenia:

echo $(( 024 ))

Usuń wiodące zera za pomocą przykładów kodu z kodu @ steeldriver w komentarzu poniżej.

nsilent22
źródło
1
Nie powinno być potrzeby uciekania się sedtutaj: użyj formatu daty, %-jaby wyeliminować dopełnianie zera u źródła, użyj jawnej podstawy w powłoce 10#$current_datelub usuń wiodące zero za pomocą podstawienia parametrów${current_date#0}
steeldriver