BASH - skrypt zwraca błąd przy inkrementacji "08"

Potrzebujesz pomocy z C, C++, perl, python, itp.
Awatar użytkownika
chivito
Posty: 4
Rejestracja: 02 maja 2020, 12:31
Lokalizacja: Pszczyna

BASH - skrypt zwraca błąd przy inkrementacji "08"

Post autor: chivito » 02 maja 2020, 12:57

Witam, wszystkich
Jestem nowym użytkownikiem na forum oraz w skryptach bashu.

Natrafiłem na taką sytuację jak w skrypcie poniżej.

Kod: Zaznacz cały

#!/bin/bash
while [ 1 ] ; do
	#Tsec=$(date '+%S')
	Tsec="08"
	
	echo "sec in $Tsec"
	
	#Tsec=$((Tsec+0))
	Tsec=$((Tsec*1))
	echo "sec out $Tsec"
	sleep 1
done
I pytanie dlaczego sekunda ma wartość "08" skrypt sie wysypuje zwracając komunikat:
./format.sh: linia 14: 08: wartość za duża na podstawę (błędny znacznik to "08")
Programowaniem zajmuję się czysto hobbystycznie i nie do końca mam ogarniętą nomenklaturę.
W googlu nie udało mi się znaleźć odpwiedzi.
Ostatnio zmieniony 02 maja 2020, 18:00 przez chivito, łącznie zmieniany 1 raz.

Awatar użytkownika
chivito
Posty: 4
Rejestracja: 02 maja 2020, 12:31
Lokalizacja: Pszczyna

Re: skrypt bash zwraca błąd przy inkrementacji "08"

Post autor: chivito » 02 maja 2020, 14:46

nie mam pojęcia o co chodzi ale trochę protestowałem i udało mi się uzyskać ciągłość pętli nieskończonej (już ponad godzinę) przez wstawienie dwóch if dla wartości 08 i 09 tak działa jak w kodzie poniżej:

Kod: Zaznacz cały

#!/bin/bash
while [ 1 ] ; do
	Tsec=$(date '+%S')
	
	if [ $Tsec = "08" ] ; then
		Tsec=8
	else
		if [ $Tsec = "09" ] ; then
			Tsec=9
		fi
	fi
	echo "sec in $Tsec"
	
	#Tsec=$((Tsec+0))
	Tsec=$((Tsec*1))
	echo "sec out $Tsec"
	sleep 1
done
ktoś wie może skąd to się bierze?

Awatar użytkownika
dedito
Moderator
Posty: 3171
Rejestracja: 18 listopada 2013, 21:07
Lokalizacja: Gliwice

Re: skrypt bash zwraca błąd przy inkrementacji "08"

Post autor: dedito » 02 maja 2020, 14:49

Ten skrypt nie ma linii 14.
Błąd dotyczy linijki gdzie wykonujesz mnożenie Tsec=$((Tsec*1))
Jak chcesz mieć Tsec w formacie dwucyfrowym to rób to przy wyświetlaniu np. $(printf %02d $Tsec)

Awatar użytkownika
chivito
Posty: 4
Rejestracja: 02 maja 2020, 12:31
Lokalizacja: Pszczyna

Re: skrypt bash zwraca błąd przy inkrementacji "08"

Post autor: chivito » 02 maja 2020, 16:33

potrzebuję uzyskać bufor czasowy 1 sekundy do pobrania czasów z mysql, dla tego pobieram aktualną wartość sekund i ją inkrementuję.
w skrypcie głównym błąd generuje to miejsce:

Kod: Zaznacz cały

Tsec=$(date '+%S')
Tsec=$((Tsec+1))
echo użyłem tylko w skrypcie do testowania tego błędu. Błąd pojawia się taki sam i w tych samych sytuacjach.
Samo przypisanie Tsec=$(date '+%S') daje zawsze format dwucyfrowy.
Myślę że nie było by problemu gdy zwracana wartość była od 0...59 a nie od 00...59 tyle że w man dla date znałem instrukcje tylko dla godzini '+%k', która zwraca 0..23 a dla minut i sekund nie.

dzieje się tak samo dla każdej instrukcji #1 #2 #3

Kod: Zaznacz cały

#!/bin/bash
while [ 1 ] ; do
	Tsec=$(date '+%S')
	Tsec=$((Tsec+0))  #1
	#Tsec=$((Tsec+1)) #2
	#Tsec=$((Tsec*1)) #3
	echo "sec out $Tsec"
	sleep 1
done
działania wykonują się poprawnie gdy Tsec na wejściu zawiera 00...07 i 10...59
natomiast błąd pojawia się tak samo dla Tsec 08 i 09

Obrazek

Awatar użytkownika
dedito
Moderator
Posty: 3171
Rejestracja: 18 listopada 2013, 21:07
Lokalizacja: Gliwice

Re: BASH - skrypt zwraca błąd przy inkrementacji "08"

Post autor: dedito » 02 maja 2020, 19:06

chivito pisze:
02 maja 2020, 16:33
Myślę że nie było by problemu gdy zwracana wartość była od 0...59 a nie od 00...59 tyle że w man dla date znałem instrukcje tylko dla godzini '+%k', która zwraca 0..23 a dla minut i sekund nie.
Może nie jest to zbyt jasno opisane, ale w moim man date jest takie coś:
Domyślnie, date wypełnia pola numeryczne zerami. Następujące opcjonalne
modyfikatory mogą być umieszczone po %:

- (łącznik) nie wypełnia pola
Pobieraj sekundy bez zer wiodących.

Kod: Zaznacz cały

Tsec=$(date '+%-S')

Awatar użytkownika
lizard
Beginner
Posty: 277
Rejestracja: 08 lutego 2016, 18:47

Re: BASH - skrypt zwraca błąd przy inkrementacji "08"

Post autor: lizard » 03 maja 2020, 18:20

W powłoce zapis 0n oznacza zapis w notacji ósemkowej, gdzie nie występują cyfry 8 ani 9.

Bash posiada zmienną SECONDS, która zlicza sekundy od uruchomienia powłoki. Jest ona zapisywalna, więc można ja wyzerować:

Kod: Zaznacz cały

SECONDS=0
while true; do             # ładniejsze od 'while [1]'
  echo "sec out $SECONDS"
  sleep 1
done
Jak chcesz zamienić ciąg znaków wyglądających jak liczba całkowita na liczbę użyj: expr $Tsec + 0. Spacje są obowiązkowe.

Awatar użytkownika
chivito
Posty: 4
Rejestracja: 02 maja 2020, 12:31
Lokalizacja: Pszczyna

Re: BASH - skrypt zwraca błąd przy inkrementacji "08"

Post autor: chivito » 04 maja 2020, 20:57

Dobra powiem jak sprawa wygląda.
Ja to jestem architektem krajobrazu, który miał być elektronikiem a potem programistą.
Zamierzam postawić sterownik do nawadniania ogrodu na raspberry pi.
Interfejs napisałem w php+html z zapisem parametrów do mysql.
Skrypt w bash'u odpowiada za sterowanie czasowe, uruchamia się przez rc.local.
To jest mój pierwszy skrypt w bashu więc proszę o wyrozumiałą krytykę.
Na tą chwilę myślę że chyba powinienem go rozbić na kilka mniejszych skryptów, w tym jeden z pętlą główną.

Kod: Zaznacz cały

#!/bin/bash
#-----inicjalizacja portu GPIO
gpio write 1 1
gpio write 4 1
gpio write 5 1
gpio write 6 1
gpio write 10 1
gpio write 11 1
gpio write 31 1
gpio write 26 1
gpio write 27 1
gpio write 28 1

gpio mode 1 out
gpio mode 4 out
gpio mode 5 out
gpio mode 6 out
gpio mode 10 out
gpio mode 11 out
gpio mode 31 out
gpio mode 26 out
gpio mode 27 out
gpio mode 28 out

#-----odczekanie 30 sekund od startu systemu
x=0;

while [ $x -le 26 ] ; do
	echo "$MESSAGE sec $x/30"
	x=$((x+5));
	sleep 5
done

#----pobranie aktualnego czasu
Thr=$(date '+%-H')
Thr=$((Thr+1))
if [ $Thr -eq 24 ] ; then
	Thr=0;
fi	
Tmin=$(date '+%-M')
Tsec=$(date '+%-S');
echo "godzina = $Thr"
echo "minuta = $Tmin"
echo "sec = $Tsec"

Tsec=$((Tsec+10))
if [ $Tsec -gt 59 ] ; then
	Tsec=$((Tsec - 59))
fi
rr=0;
echo "sec = $Tsec"
#pobranie kolejnego startu jesli jest dostepny przed godzina 00:00:00
tab=$(echo "SELECT COUNT(*) FROM start_time WHERE ( hr=$Thr AND min>=$Tmin ) OR hr>$Thr" | mysql -Dhomster -u user -ppasss -N)
StartNr="${tab[0]}";
echo "ilość startów przed nami: $StartNr"
if [ $StartNr -gt 0 ] ; then
	tab=$(echo "SELECT hr FROM start_time WHERE ( hr=$Thr AND min>=$Tmin ) OR hr>$Thr  ORDER by hr, min LIMIT 1" | mysql -Dhomster -u user -ppasss -N)
	StartHr="${tab[0]}";
	tab=$(echo "SELECT min FROM start_time WHERE ( hr=$Thr AND min>=$Tmin ) OR hr>$Thr  ORDER by hr, min LIMIT 1" | mysql -Dhomster -u user -ppasss -N)
	StartMin="${tab[0]}";
	echo "kolejny start: $StartHr:$StartMin"
fi

#----ZEROWANIE POLECENIA SLEEP
Tsec=$(date '+%-S');
rr=$Tsec;
while [ $Tsec -eq $rr ] ; do
	rr=$(date '+%-S');
done


#-----AKTUALIZACJA CZASU -----
Thr=$(date '+%-H')
Thr=$((Thr+1));
if [ $Thr -eq 24 ] ; then
	Thr=0;
fi
Tmin=$(date '+%-M')
Tsec=$(date '+%-S')

StartJuz=0
rr=0;

#-----PETLA GLOWNA -----
while [ $rr -le 10 ] ; do # petla glowna
	Tsec=$(date '+%-S')
	echo "time $Thr:$Tmin:$Tsec"
	
	if [ $Tsec -eq 0 ] ; then # zerowa sekunda
		Tmin=$(date '+%-M')
		if [ $Tmin -eq 0 ] ; then # zerowa minuta
			Thr=$(date '+%-H')
			Thr=$((Thr+1));
			if [ $Thr -eq 24 ] ; then # zerowa godzina
				Thr=0;
				#pobranie pierwszego startu jesli jest dostepny przed godzina 00:00:00
				
				tab=$(echo "SELECT COUNT(*) FROM start_time WHERE ( hr=$Thr AND min>=$Tmin ) OR hr>$Thr" | mysql -Dhomster -u user -ppasss -N)
				StartNr="${tab[0]}";
				echo "ilość startów przed nami: $StartNr"
				if [ $StartNr -gt 0 ] ; then
					tab=$(echo "SELECT hr FROM start_time WHERE ( hr=$Thr AND min>=$Tmin ) OR hr>$Thr ORDER by hr, min LIMIT 1" | mysql -Dhomster -u user -ppasss -N)
					StartHr="${tab[0]}";
					tab=$(echo "SELECT min FROM start_time WHERE ( hr=$Thr AND min>=$Tmin ) OR hr>$Thr ORDER by hr, min LIMIT 1" | mysql -Dhomster -u user -ppasss -N)
					StartMin="${tab[0]}";
					echo "kolejny start: $StartHr:$StartMin"
				fi # koniec pobierania czasu startu z bazy danych
			fi # koniec ustawiania godziny 0
		fi #koniec ustawiania godzin
		
		if [ $StartNr -gt 0 ] ; then # jesli jest nastepny start
			if [ $Thr -eq $StartHr ] ; then # oczekiwanie na godzine startu
				if [ $Tmin -eq $StartMin ] ; then # oczekiwanie na minute startu
#-- START PROGRAMU -------------------------------------------------------------	
					echo "run program:"
					mysql -u user -ppasss -Dhomster -e"UPDATE start_time SET stan=1 WHERE hr=$StartHr AND min=$StartMin;" 
					StartJuz=1
					
				fi #koniec oczekiwania na minute startu
			fi #koniec oczekiwania na godzine startu
		fi #koniec oczekiwania na start
	fi #koniec ustawiania minut
	
#-- OBSLUGA PROGRAMU ------------------------------------------------------------
	if [ $StartJuz -eq 1 ] ; then 
		
		#pobieranie liczby sekcji do uruchomienia
		tab=$(echo "SELECT COUNT(*) FROM item WHERE typid=2" | mysql -Dhomster -u user -ppasss -N)
		num="${tab[0]}";
		id=0;
		#rozruch
		gpio write 1 0 # wlaczenie pompy
		mysql -u user -ppasss -Dhomster -e"UPDATE item SET stan=0 WHERE gpio=1;" 
		echo "ilosc sekcji: $num"
		x=0;
		while [ $x -lt $num ] ; do # petla pracy i przelaczania sekcji
			x=$((x+1));
			
			tab=$(echo "SELECT gpio FROM item WHERE id>$id AND typid=2 LIMIT 1" | mysql -Dhomster -u user -ppassss -N) 
			Vgpio="${tab[0]}";
			tab=$(echo "SELECT stime FROM item WHERE id>$id AND typid=2 LIMIT 1" | mysql -Dhomster -u user ppasss -N) 
			Stime="${tab[0]}";
			tab=$(echo "SELECT nazwa FROM item WHERE id>$id AND typid=2 LIMIT 1" | mysql -Dhomster -u user -ppasss -N) 
			Sname="${tab[0]}";
			tab=$(echo "SELECT id FROM item WHERE id>$id AND typid=2 LIMIT 1" | mysql -Dhomster -u user -ppasss -N) 
			id="${tab[0]}";

			echo "$x $Sname"
			echo "gpio $Vgpio"
			echo "time $Stime"
			echo "----------"
			gpio write $Vgpio 0
			mysql -u user -ppasss -Dhomster -e"UPDATE item SET stan=0 WHERE gpio=$Vgpio;" 
			sleep $Stime
			gpio write $Vgpio 1
			mysql -u user -ppasss -Dhomster -e"UPDATE item SET stan=1 WHERE gpio=$Vgpio;" 
		done #koniec pracy przelaczania sekcji
		
		gpio write 1 1 # wylaczenie pompy
		mysql -u user -ppasss -Dhomster -e"UPDATE item SET stan=1 WHERE gpio=1;" 
		mysql -u user -ppasss -Dhomster -e"UPDATE start_time SET stan=0 WHERE hr=$StartHr AND min=$StartMin;" 
		
#-- SPRAWDZENIE CZY JEST KOLEJNY START

		#sprawdzenie bierzacego czasu
		Thr=$(date '+%-H')
		Thr=$((Thr+1));
		if [ $Thr -eq 24 ] ; then
			Thr=0;
		fi
		Tmin=$(date '+%-M')
		Tsec=$(date '+%-S')
		Tsec=$((Tsec+10))
		if [ $Tsec -gt 59 ] ; then
			Tsec=$((Tsec - 59))
		fi
		#pobranie pierwszego startu jesli jest dostepny przed godzina 00:00:00
		tab=$(echo "SELECT COUNT(*) FROM start_time WHERE ( hr=$Thr AND min>=$Tmin ) OR hr>$Thr" | mysql -Dhomster -u user -ppasss -N)
		StartNr="${tab[0]}";
		echo "ilość startów przed nami: $StartNr"
		if [ $StartNr -gt 0 ] ; then
			tab=$(echo "SELECT hr FROM start_time WHERE ( hr=$Thr AND min>=$Tmin ) OR hr>$Thr  ORDER by hr, min LIMIT 1" | mysql -Dhomster -u user -ppasss -N)
			StartHr="${tab[0]}";
			tab=$(echo "SELECT min FROM start_time WHERE ( hr=$Thr AND min>=$Tmin ) OR hr>$Thr  ORDER by hr, min LIMIT 1" | mysql -Dhomster -u user -ppasss -N)
			StartMin="${tab[0]}";
			echo "kolejny start: $StartHr:$StartMin"
		fi # koniec pobierania czasu startu z bazy danych
		
		#----ZEROWANIE POLECENIA SLEEP
		Tsec=$(date '+%-S');
		rr=$Tsec;
		while [ $Tsec -eq $rr ] ; do
			rr=$(date '+%-S');
			rr=$((rr+0))
		done
		rr=0
		Thr=$(date '+%-H')
		Thr=$((Thr+1));
		if [ $Thr -eq 24 ] ; then
			Thr=0;
		fi
		Tmin=$(date '+%-M')
		Tsec=$(date '+%-S')
		StartJuz=0 # zerowanie wyzwolenia startu pracy
	else
		sleep 1
	fi
done #koniec petli glownej

Awatar użytkownika
LordRuthwen
Moderator
Posty: 2149
Rejestracja: 18 września 2009, 21:45
Lokalizacja: klikash?

Re: BASH - skrypt zwraca błąd przy inkrementacji "08"

Post autor: LordRuthwen » 06 maja 2020, 11:36

A nie próbowałeś użyć jakiegoś gotowca? Przecież takich projektów na RPi jest od groma.

ODPOWIEDZ