Habe zwei kleine Scripte geschrieben, die für manch einen ganz nützlich sein könnten. Vor allem, wenn man an einem RPi-Radiowecker oder ähnlichem arbeitet. Sollte jemand Lust haben ein Zeitansage- oder Datumsansage-Shellscript für eine andere Sprache (Englisch, Französisch, Spanisch...) zu schreiben, könnte man ja eine kleine Sammlung daraus machen. Ich habe selbst nur wenig Ahnung vom Programmieren und das ganze einfach mal zusammengehackt. Eignet sich also gut für Anfänger.
Zeitansage-Script + Datumsansage-Script
-
belvsdragon -
5. März 2014 um 19:59 -
Erledigt
Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
-
-
Zeitansage-Script + Datumsansage-Script? Schau mal ob du hier fündig wirst!
-
Hehe... Das is ja witzig.
Genau sowas hatte ich noch gebraucht.
Bisher hatte ich für Zeit und Datum einzelne Soundfiles erstellt und die mithilfe einer kleinen Routine zusammengesetzt. Mir war klar, das es eine Sprachausgabe geben müsste, hatte bisher aber noch nicht danach gesucht. Denn mit meinem jetzigem System kann ich die Stimme auch selber einsprechen.Die Stimme von dem Onkel ist zwar nicht so angenehm wie meine Google-Tante, lässt sich aber wunderbar für ungeplante Sprachausgabe nutzen (neue Radiosender oder vorlesen von Radiotext z.B.).
Echt geil! Danke dafür!
Vllt. sollte man für Anfänger noch erwähnen das man espeak installieren und die Datei ausführbar machen muss.
-
-
LieberScholli: Danke für deine Ergänzungen zur Scriptausführung. Freut mich ja, dass dir das Script nützt.
BooStar: Habe mir eben mal angeschaut, wie das mit case-Anweisungen funktioniert und das ganze gleich mal ausprobiert. Ist wirklich deutlich übersichtlicher!Falls sich jemand wundert, warum die eSpeak-Ausgabe in eine wave-Datei umgeleitet wird, welche dann vom omxplayer wiedergegeben und am Ende gelöscht wird: Die direkte eSpeak-Ausgabe läuft manchmal nicht ganz optimal.
Codeespeak -vde "Es ist $hours Uhr $minutes." -w tts_time_de1 omxplayer tts_time_de1 rm tts_time_de1
Es würde aber theoretisch auch so funktionieren:
Die neue Version von tts_date_de1.sh mit case-Anweisungen hab ich an den Beitrag drangehängt.
-
Ich versteh nicht ganz wieso in der tts_time_de1.sh date +%k genutzt wird?
Wieso wird das überhaupt teilweise in Worte verändert aber teilweise bleibt es bei Zahlen
Anfängerfreundlich wäre es wenn in den Scripts Kommentare stünden wieso etwas gemacht wird...
Aber wirklich super und vorbildlich das du deinen Code der Community ungefragt bereitstellst :thumbs1:
das ist leider keine Selbstverständlichkeit mehr, sondern nimmt sogar leider immer weiter ab Fragen wie was umgesetzt werden kann gibts zu hauf aber letzlich die Umsetzung oder das Ergebnis wird für sich behalten
-
Zitat
Ich versteh nicht ganz wieso in der tts_time_de1.sh date +%k genutzt wird?Ich auch nicht. Wie gesagt, ich hab das einfach mal so zusammengehackt und es funktioniert auch ohne Fehler, aber dass einiges logisch nicht ganz konsistent ist, war mir gleich klar. Ich hab vorher so gut wie nichts selbst programmiert.
Aber der Hinweis ist, glaube ich ganz gut. Es gibt bei date 4 Varianten für Stundenangaben:
%H Stunde (00..23).
%I Stunde (01..12).
%k Stunde, mit Leerzeichen auf zwei Stellen aufgefüllt ( 0..23).
%l Stunde, mit Leerzeichen auf zwei Stellen aufgefüllt ( 1..12).und dann gibt es ja noch = und ==.
Ich hab generell %k benutzt, weil hier 1,2,3,4 gezählt wird und nicht 01,02,03,04 wie beispielsweise bei %H. eSpeak würde im Fall von
nicht "Es ist zwei Uhr..." lesen, sondern es ist "Es ist null zwei Uhr..." ausgeben.
Zitat
Wieso wird das überhaupt teilweise in Worte verändert aber teilweise bleibt es bei ZahlenAlso Worte werden immer dann verwendet wenn eSpeak das sonst falsch aussprechen würde.
Zitat
Anfängerfreundlich wäre es wenn in den Scripts Kommentare stünden wieso etwas gemacht wird...Mach ich vielleicht noch. Wollte mir erst einmal anschauen, wie andere ihre Scripte so durchkommentieren. Ich bin ja selbst Anfänger und da ich es hinbekommen habe, es zu schreiben, sollte eigentlich jeder der die manpages von date und espeak lesen kann, und sich kurz mit Shellscripten beschäftigt, nach einer Weile eine nette Stimme aus seinen Lautsprechern hören.
Man könnte nämlich noch weitere Varianten schreiben, wie z.B. "Es ist viertel nach acht.".
Deshalb die Namensgebung:tts Text-to-Speech
time ist klar, aber ich hab auch noch ein halbfertiges Script für "Guten morgen." "Guten Abend"... für die jeweilige Tageszeit. Deswegen könnte man auch hier noch greetings-Scripte und ähnliches basteln.
de1
weitere Varianten wären dann en, es, fr, --> Englisch, Spanisch, Französisch
oder de2 für die "Es ist viertel nach acht."-Version und so weiter. -
Wenn ihr das für Multilanguage umschreiben wollt kann ich euch eine einfache Vorlage geben mit der ihr nur ein Script benötigen würdet hoffe nur das ich das verständlich genug Beschreiben kann
Also was man nur bräuchte wäre ein Script was die Ausgabe macht und in dem die Sprache festgelegt wird - optional könnte man aber auch zusätzlich eine Konfigurationsdatei anlegen in der die Sprache festgelegt wird..
Dann erstellt man Language Files in denen die Sätze hinterlegt sind aber mit einheitlichen Variablen, also zum Beispiel:
lang_de.sh
lang_en.sh
Und im eigentlichen Script prüft man dann welche Language eingestellt wurde und inkludiert dann das entsprechende Language-File:
tts_time.sh
Bash
Alles anzeigen#!/bin/bash DEFAULTlanguage="de" for l in $(ls lang_*); do lang=$(echo $l | sed 's/lang_//g') if [ "$DEFAULTlanguage" == "$(basename $lang .sh)" ]; then . $l break fi done if [ "`date +%k`" = "1" ]; then hours=ein else hours=`date +%k` fi if [ "`date +%-M`" = "0" ]; then minutes=" " else minutes=`date +%-M` fi espeak -vde "${ItIs} $hours ${Clock} $minutes." -w tts_time_1 omxplayer tts_time_1 rm -f tts_time_1
Die Schreibweise der for Schleife ist Absicht, also insbesondere der Punkt und das Leerzeichen ist hierbei wichtig, da wir das Script nicht ausführen sondern einlesen, also dessen Variablen inkludieren, wollen
Auf diese Art braucht ihr quasi nur lang_X.sh zu erstellen
-
Prinzipiell finde ich die Idee ziemlich gut. Das hätte den Vorteil, dass man relativ einfach andere Sprachen hinzufügen könnte. Ich bin mir nur nicht sicher ob das so funktioniert. Aus dem Bauch heraus würde ich jetzt darauf tippen, dass einem an irgendeiner Stelle die Syntax irgendeiner Sprach einen Strich durch die Rechnung macht und man am Ende dann doch wieder diese Zeile hier anders schreiben muss:
Deswegen würde ich jetzt eher dazu tendieren, die Scripte einzeln zu lassen. Aber ich muss auch zugeben, dass ich die for-Schleife nicht wirklich kapiere. Muss ich mir mal genauer anschauen. Kann also auch sein, dass es am Verständnis liegt.
-
Das versteh ich jetzt irgendwie nich
Selbst wenn der Satzbau in einer anderen Sprache anders wäre, könnte man das flexibel regeln - habe mir die Mühe jetzt nur nicht gemacht ums nicht allzu kompliziert wirken zu lassenMan kann mit 'Platzhalter'n arbeiten und in den lang_X.sh Dateien die vollständigen Sätze mit Platzhalter einfügen. Im Script wird dann der Platzhalter mit der entsprechenden Variablen ersetzt und friedefreudeeierkuchen
lang_de.sh
CodeTIME="Es ist %HOUR% %CLOCK% %MINUTE%" DATE="Heute ist %DAYNAME% %THE% %DAY% %MONNAME% %YEAR%." THE="der" CLOCK="Uhr"
lang_en.sh
CodeTIME="It is %HOUR% %CLOCK% %MINUTE%" DATE="Today is %DAYNAME% %THE% %DAY% %MONNAME% %YEAR%." THE="the" CLOCK="clock"
tts_time.sh
Spoiler anzeigen
Bash
Alles anzeigen#!/bin/bash DEFAULTlanguage="de" for l in $(ls lang_*); do lang=$(echo $l | sed 's/lang_//g') if [ "$DEFAULTlanguage" == "$(basename $lang .sh)" ]; then . $l break fi done if [ "`date +%k`" = "1" ]; then hours=ein else hours=`date +%k` fi if [ "`date +%-M`" = "0" ]; then minutes=" " else minutes=`date +%-M` fi TIME=${TIME//%HOUR%/$hours} TIME=${TIME//%CLOCK%/$CLOCK} TIME=${TIME//%MINUTE%/$minutes} espeak -vde "$TIME" -w tts_time_1 omxplayer tts_time_1 rm -f tts_time_1
tts_date.sh
Spoiler anzeigen
Bash
Alles anzeigen#!/bin/bash case "`date +%e`" in " 1") day=erste ;; " 2") day=zweite ;; " 3") day=dritte ;; " 4") day=vierte ;; " 5") day=fünfte ;; " 6") day=sechste ;; " 7") day=siebte ;; " 8") day=achte ;; " 9") day=neunte ;; "10") day=zehnte ;; "11") day=elfte ;; "12") day=zwölfte ;; "13") day=dreizehnte ;; "14") day=vierzehnte ;; "15") day=fünfzehnte ;; "16") day=sechzehnte ;; "17") day=siebzehnte ;; "18") day=achtzehnte ;; "19") day=neunzehnte ;; "20") day=zwanzigste ;; "21") day=einundzwanzigste ;; "22") day=zweiundzwanzigste ;; "23") day=dreiundzwanzigste ;; "24") day=vierundzwanzigste ;; "25") day=fünfundzwanzigste ;; "26") day=sechsundzwanzigste ;; "27") day=siebenundzwanzigste ;; "28") day=achtundzwanzigste ;; "29") day=neunundzwanzigste ;; "30") day=dreißigste ;; "31") day=einunddreißigste ;; esac DATE=${DATE//%DAYNAME%/`date +%A`} DATE=${DATE//%THE%/$THE} DATE=${DATE//%DAY%/$day} DATE=${DATE//%MONNAME%/`date +%B`} DATE=${DATE//%YEAR%/`date +%Y`} espeak -vde "$DATE" -w tts_date_de1 omxplayer tts_date_de1 rm tts_date_de1
-
Zitat
Das versteh ich jetzt irgendwie nich
Selbst wenn der Satzbau in einer anderen Sprache anders wäre, könnte man das flexibel regeln - habe mir die Mühe jetzt nur nicht gemacht ums nicht allzu kompliziert wirken zu lassen
Man kann mit 'Platzhalter'n arbeiten und in den lang_X.sh Dateien die vollständigen Sätze mit Platzhalter einfügen. Im Script wird dann der Platzhalter mit der entsprechenden Variablen ersetzt und friedefreudeeierkuchenAlso ich glaube, das ist jetzt alles nicht mehr so ganz mein Level. Aber ich würd mich freuen, wenn du das ganze weiterentwickelst.
Ich finde, man könnte ja mal eine Shell-Scripte Sammlung für den Raspberry Pi machen. Es gibt ja einige nützliche Sachen, die nur ziemlich verstreut im Netz herumliegen. Und da das meiste unter CC oder ähnlichen Lizensen steht wäre es ja ganz praktisch das alles mal zu einem Paket zu verschnüren. Mir fällt da zum Beispiel Bashpodder ein (http://lincgeek.org/bashpodder/)...
-
Was nicht ist kann ja noch werden
Eigentlich ist das nicht sooo schwer, ich versuchs mal zu erklärn was das alles so macht:
Codefor l in $(ls lang_*); do lang=$(echo $l | sed 's/lang_//g') if [ "$DEFAULTlanguage" == "$(basename $lang .sh)" ]; then . $l break fi done
Die for Schleife dreht sich halt für den "in" Inhalt im Kreis, arbeitet das also ab.
$(ls lang_*) ... enthält die Rückgabe des Befehls ls lang_* , es werden also im aktuellen Verzeichnis alle Dateien gelistet die auf lang_* zutreffen: lang_de.sh lang_en.sh usw
$( ) ist vergleichbar mit ``man könnte das also auch so schreiben: `ls lang_*` ... nur finde ich meine gewählte Schreibweise übersichtlicher, als würde man eben eine Variable nutzenlang=$(echo $l | sed 's/lang_//g') ... dort wird von der for Schleife $l ausgegeben und an den sed Befehl gepiped (übergeben). Der sed Befehl ersetzt alle Vorkommen von lang_ und ersetzt es mit <nichts>, es wird also rausgelöscht -> lang_de.sh wird dadurch zu de.sh
if [ "$DEFAULTlanguage" == "$(basename $lang .sh)" ]; then ... if-Bedingungsvergleich kennste ja scho..
'The Magic' hierbei ist denk ich $(basename $lang .sh) -> basename ist ein allgemeiner Befehl (wie auch dirname) welcher aus einer Pfadangabe nur den Dateinamen ausgibt und der 2.Parameter .sh sorgt dafür dass die Dateiendung .sh ebenfalls rausgeschnitten wird. Würde man zum Beispiel basename /var/log/auth.log in die Konsole eingeben würde er nur auth.log zurück geben. Würde man basename /var/log/auth.log .log eingeben käme nur auth zurück..
Dadurch erreicht man also das aus der zuvor bearbeiteten $l -> lang_de.sh -> de.sh und dann nur noch -> de wird, und somit für den if Vergleich erst brauchbar wäre
Ist die if Bedingung erfüllt wird . $l geladen -> lang_de.sh ... Das ist hierbei wie gesagt kein Ausführen sondern Inkludieren, wir fügen also den Inhalt der Datei in das aktuelle Script mit ein. Die Dateien könnten auch ohne Dateiendung sein das würde keine Rolle spielen.
Anschließend unterbrechen und beenden wir die for Schleife mithilfe von break , da wir ja eine passende Datei gefunden haben brauchen wir auch nicht noch mehr Zeit/CPU-last verschwenden
(man könnte auch continue nutzen dann würde er weiter unten stehenden Code nicht mehr beachten und zum nächsten for-Durchlauf springen - aber das nur nebenbei)Das nächste was denk ich unklar ist wären dann diese Platzhalter:
Dies ist eine allgemeine bash Funktion, sh kann das noch nicht (bash ist neuer als sh), und ist ein spezieller Umgang mit Variablen - das macht im Prinzip das selbe wie beim zuvor behandelten sed Befehl -> Es ersetzt ein Vorkommen:
Der Inhalt der Variable $TIME wird nach %HOUR% durchsucht und alle Vorkommen werden durch den Inhalt der Variablen $hours ersetzt
Wenn $hour=12 und TIME="Es ist %HOUR% %CLOCK% %MINUTE%" ist dann durchsucht er "Es ist %HOUR% %CLOCK% %MINUTE%" nach %HOUR% und ersetzt dies durch den Variablen-Inhalt von $hours -> "Es ist 12 %CLOCK% %MINUTE%"Verstanden?
-
Das ist wirklich mal eine super Erklärung! Die for-Schleife, sed, basename und das mit dem Inkludieren hab ich soweit verstanden. Das mit
muss ich mir nochmal näher anschauen. Trotzdem: Wieder was gelernt!
Ich hab mal ein paar Fragen/Aussagen versammelt, die dafür Sprechen würden doch Einzelscripte zu verwenden. So ganz will mir dieser Ansatz nämlich nicht aus dem Kopf gehen.Was ist, wenn ich verschiedene Cronjobs anlegen will und zu verschiedenen Tageszeiten unterschiedliche Sprachen bei der Zeitansage nehmen will?
Ist das dann nicht flexibler für jede Sprache ein einzelnes Script zu nehmen?Würde das nicht auch mehr dem KISS-Prinzip entsprechen?
Wenn ich mich schon schwer mit der Auslagerung in verschiedene Sprachdateien tue... Wäre bestimmt anfängerfreundlicher.Ich sehe die Hackability des ganzen auch größer, wenn jedes Script für sich funktioniert und einfach in ein anderes Script reinkopiert werden kann.
Verständnisfrage: Wenn die ganzen If-Anweisungen für sprachliche Unregelmäßigkeiten wie das "Es ist ein(s) Uhr"-Problem auch in die Sprachdateien wandern, ist dann das Hauptscript sowieso nicht ziemlich leer?
Wird das nicht ziemlich unübersichtlich, wenn man für eine Sprache 3 verschiedene Versionen macht und alles einer Datei versammelt?
-
Wie auch an Befehle kannst du auch an Scripte sog. Parameter (oder Argumente) übergeben. Wie zum Beispiel beim Befehl ls mit dem Zusatz -la --> ls -la ... dann wäre -la ein Parameter für ls
Parameter werden durch Leerzeichen getrennt, also jedes Leerzeichen zwischen den Parametern kennzeichnet ein weiteren Parameter, nur mal als Beispiel: befehl a b c d
Dann ist a der erste Parameter, b der 2.Parameter, c der 3.Parameter uswBeim bash Script wird das anhand von $1 fürs 1. Parameter, $2 fürs 2. Parameter, $3 fürs dritte usw - oder $* bzw $@ für alle...
Nur nebenbei erwähnt: Wenn man nicht das erste aber flexibel alle weiteren Parameter weiter nutzen will kann man folgendes nutzen:
cut "schneidet" etwas aus, erkennt das anhand eines Leerzeichens (-d ' ' ) und gibt dann nur die Felder 2 bis Ende aus ( -f 2- )
Man könnte das Script also so gestalten dass wenn ein Parameter übergeben wird eine bestimmte Aktion auszuführen:
wenn also ein 1.Parameter übergeben wurde, also $1 nicht leer ist (anstatt ! -z könnte man auch -n nutzen), wird das echo ausgeführt und danach das Script beendet.. Wenn $1 aber leer oder nicht gesetzt (also nicht übergeben) wurde, wird der nachfolgende Code ausgeführt
Bezüglich "Es ist ein(s) Uhr"-Problem: Die if Schleife auch noch in die Sprachdateien auszulagern würde in diesem Fall nichts bringen, also nicht die if schleifen ansich, da an die lang_de.sh Dateien keine Parameter übergeben werden sondern nur der Inhalt der Datei ausgelesen wird
Eigentlich programmiert man modular bzw mit Templates. Sprachen kann man so einfacher hinzufügen als jedesmal den Quellcode des "Programms" duplizieren zu müssen. Ausserdem will man nicht 20x den eigentlichen Code bearbeiten/verändern/optimieren sondern eben nur ein mal Immer wiederkehrende Abläufe packet man zB auch in sog. Functions (Anweisungen), damit man diese nicht 20x bearbeiten muss wenns dort nen Fehler gab oder man diese erweitern möchte sondern eben nur ein mal und der Aufruf bleibt gleich..
Also zum Beispiel: -
Ich finde, man könnte ja mal eine Shell-Scripte Sammlung für den Raspberry Pi machen. Es gibt ja einige nützliche Sachen, die nur ziemlich verstreut im Netz herumliegen.
Das würde ich auch begrüßen. Hätte auch das ein oder andere Skript zum einstellen :thumbs1:
-
Zitat
Eigentlich programmiert man modular bzw mit Templates. Sprachen kann man so einfacher hinzufügen als jedesmal den Quellcode des "Programms" duplizieren zu müssen. Ausserdem will man nicht 20x den eigentlichen Code bearbeiten/verändern/optimieren sondern eben nur ein mal Icon_wink Immer wiederkehrende Abläufe packet man zB auch in sog. Functions (Anweisungen), damit man diese nicht 20x bearbeiten muss wenns dort nen Fehler gab oder man diese erweitern möchte sondern eben nur ein mal und der Aufruf bleibt gleich..
Also ich hatte mich vor kurzem mal an einer Zeitansage auf Spanisch versucht und da stößt man auf ganz andere Probleme als im Deutschen. Aber vielleicht lässt sich das ja trotzdem so modular, wie du das vorschlägst, vereinfachen. Das wäre natürlich professioneller. :thumbs1:
ZitatDas würde ich auch begrüßen. Hätte auch das ein oder andere Skript zum einstellen
Hab mal ein Thread dazu aufgemacht: Raspberry Pi-Shell-Scripte-Sammlung
-
Es gibt jetzt ein Github-Repository dafür:
https://github.com/danielfink/zeitansageDie Scripte sind nun etwas besser dokumentiert und ich habe alles auf deutschsprachige Nutzer ausgelegt.
-
Hab ich glaub ich schon mal erwähnt: Linux mag Umlaute nicht besonders, am besten wärs diese anders zu schreiben:
ä -> ae
ö -> oe
ü -> ue
ß -> ssDas sieht man leider auch an deinem Code auf Github von Datumsansage.sh :
usw ... da ist der Zeichensatz also schon bei dir kaputtUnd Btw: Manche Monate haben mehr als 30 Tage
-
Das mit den Umlauten hab ich selbst grad schon bemerkt. Ich hatte über putty ins Webinterface von Github rüberkopiert und putty mag Umlaute nicht. Dabei ist mir wohl auch die Zeile mit der 31 abhanden gekommen. Habs korrigiert!
-
Doch, auch PuTTY zeigt Umlaute wenn mans entsprechend einstellt Aber kaum einer macht das und Linux hat wie gesagt allgemein Probleme mit Umlauten oder nicht-englisch-typischen-zeichen
-> [Tutorial] Wie stelle ich in Putty den richtigen Zeichensatz ein?
-
Da hat der schon ein Tutorial dafür geschrieben. Ich glaub es nicht! :thumbs1:
Das mit den Umlauten bei der Datumsansage funktioniert aber soweit. Kann man auch nicht vermeiden, sonst liest eSpeak das falsch.
Jetzt mitmachen!
Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!