(1) Erkennen der Frage nach einem Witz.

Da du anscheinend schon einen funktionierenden Chatbot hast, sollte das ja recht einfach gehen. Du musst also nur z.B. die Keywords Witz, lustig, etc. hinzufügen.

(2) Metadaten über deine Witzdatei erfassen.

Du brauchst hier lediglich die Anzahl an Zeilen, um dir später dann eine davon zufällig aussuchen zu können. Mit einer for-Schleife kannst du die ganz simpel zählen.

(3) Eine Zeile zufällig auswählen.

Die durch %random% generierte Zufallszahl auf den hier benötigten Zahlenbereich von [1; Zeilenlänge] bringen. Sehr simple, wenn auch nicht optimale Methode hierfür wäre:

set /a selectedLine=%random% %% lines + 1

(4) Die Zeile ausgeben.

Du traversierst hierfür alle Zeilen deiner Witze-Datei und gibst die Zeile mit der zuvor berechneten Zeilennummer aus. Dies kannst du mithilfe von findstr /n, mit einer Hilfsvariable oder mittels dekrementieren der selectedLine-Variable erledigen.

Die Schritte 2 bis 4 habe ich in dieser Antwort schon für Verzeichnisse umgesetzt:

https://www.gutefrage.net/frage/cmd-zufaelliges-wort#answer-347286974

Du musst die for-Schleifen also nur noch anpassen, dass sie sich auf Textdateien beziehen.

...zur Antwort

Ich habe vor einiger Zeit bereits auf eine ähnliche Frage geantwortet (https://www.gutefrage.net/frage/batchdatei-hoehere-zufallswert-als-32768#answer-336018767) mithilfe von diesem Code kannst du ganz einfach eine achtstellige Zufallszahl erzeugen, oder 2 vierstellige mit einem Bindestrich aneinanderhängen:

@echo off
call :randomNumber 4
set "n=%return%"
call :randomNumber 4
set "n=%n%-%return%"
echo %n%
pause & exit

:: returns random number (base 10) with %~1 digits.
:randomNumber <digits>
    setlocal enableDelayedExpansion
        set "return="
        for /L %%i in (1,1,%~1) do (
            set /a "r = (10 * !random!) / 32768"
            set "return=!return!!r!"
        )
    endlocal & set "return=%return%"
exit /b
...zur Antwort
[...] denn eigentlich kann cmd das ja nicht, deswegen brauche ich eine BATch.

Eine Batch kann in diesem Sinne auch nicht mehr, da Batch-Dateien von der cmd.exe interpretiert werden. Dir steht also standardmäßig auch nur set /a für arithmetische Operationen zur Verfügung, aber wie du richtig erkannt hast, reicht die normale Benutzung von set /a für dein Programm nicht aus.

Dividieren von Zahlen in Batch ist mithilfe von set /a aber auch "relativ" einfach mit Nachkommastellen möglich:

Eine mögliche Lösung wäre einfach den Zähler mit einer Zehnerpotenz zu multiplizieren, sodass die Genauigkeit erhöht wird. Allerdings stößt du damit schnell an eine andere Grenze der Zahlendarstellung in Batch: der Wertebereich ist auf 32-bit Integer beschränkt.

Die andere Lösung ist sich den Algorithmus zum Dividieren einfach selbst zu schreiben, wie ich es zum Beispiel bei dieser Frage hier getan hab. Allerdings hast du hier ein großes Problem: Der Algorithmus ist so geschrieben, dass er zwar Fließkommazahlen ausgibt, allerdings als Eingabeparameter nur Integer akzeptiert. Da du aber mit dem Ergebnis immer weiter rechnen willst, reicht das auch nicht aus...

Deswegen nun der finale Versuch: Nicht nur einen eigenen Algorithmus zum Dividieren schreiben, sondern einen kompletten eigenen Datentypen erstellen, auf dem die Grundrechenarten definiert sind.

Da das in Batch etwas komplex ist, kopiere ich den dementsprechend langen Code nicht hier hinein, sondern stelle ihn dir auf GitHub zum Download/Rauskopieren zur Verfügung: https://raw.githubusercontent.com/timlg07/Number.cmd/master/Number.cmd

Kopiere diesen Code in eine neue Datei "Number.cmd" und stelle sicher, dass dein Rechenprogramm darauf Zugriff hat. (Also entweder müssen beide Dateien im selben Verzeichnis liegen, deine Datei muss den Pfad von Number.cmd wissen und explizit angeben oder Number.cmd ist in einem Verzeichnis, das in %path% enthalten ist.)

Dann kannst du eine Rechnung, die mit set /a so aussehen würde:

set /a x = 4 / 5

Mithilfe von Number.cmd so hinschreiben:

Number x = 4 / 5

Um in einer Batch-Datei die Ausführung fortsetzen zu können, musst du Number.cmd callen, also so aufrufen:

call Number x = 4 / 5

Jetzt kannst du ganz trivial deine Batch verfassen und musst dir um die Zahlendarstellung (fast) keine Gedanken mehr machen. Ich habe mal schnell ein Beispiel zusammengeschrieben, bin mir aber nicht sicher, ob ich deine Folge damit richtig berechne:

@echo off
set "x=3"
set "i=1"
set "c=1"

:loop
set "operand=4"
set /a beg = c + 1
set /a mid = c + 2
set /a end = c + 3
call Number operand = %operand% / %beg%
call Number operand = %operand% / %mid%
call Number operand = %operand% / %end%

echo current iteration = %i%
echo current operand = 4 / %beg% / %mid% / %end% = %operand%

if %i% equ 2 (
	call Number x = %x% + %operand%
) else (
	call Number x = %x% - %operand%
)
echo current result = %x%
echo.

set /a i += 1
set /a c = end
goto loop

Leider ist das Dividieren die einzige Operation, die noch nicht komplett von der int32 Einschränkung befreit wurde; Daran arbeite ich gerade noch und werde die Number.cmd demnächst entsprechend anpassen.

PS: Am einfachsten (aber auch am langweiligsten 😅) ist es natürlich, eine andere Programmiersprache hierfür herzunehmen. Ich habe obige Batch mal schnell als JavaScript getippt:

var x = 3
var i = 0
var c = 1

while (i++ < 200) {
    let operand = 4 / (++c) / (++c) / (++c)
    if (i == 2) {
        x += operand
    } else {
        x -= operand
    }
    console.log(`iteration: ${i}, delta: ${operand}, new-value: ${x}`)
}

Hoffentlich konnte ich dir weiterhelfen :) Bei Unklarheiten melde dich einfach!

...zur Antwort

Du kannst mit NirCmds "win focus" ein bestimmtes Fenster fokussieren, weiteres dazu findest du hier: https://nircmd.nirsoft.net/win.html

Einen bestimmten Tab des Fensters auswählen geht von der cmd aus nur unter Verwendung von externen Tools, nur sehr sehr aufwendig und alles andere als zuverlässig, da wäre es besser du startest die Seite, die du fokussiert haben willst einfach per "start" von der Batch aus.

Das senden von Tastendrücken kannst du hingegen komplett ohne zusätzlich zu installierende Programme erledigen. Du kannst dir eine vbs Datei erstellen (manuell oder automatisch mit Batch), in der du mit CreateObject("WScript.Shell") ein shell Objekt anlegst und auf diesem dann SendKeys aufrufst.

Was hast du denn endgültig vor? Gibt es wirklich keine bessere Lösung für dein Problem, als Benutzerinteraktionen zu simulieren?

...zur Antwort

Mit einem Rubber Ducky geht das relativ einfach (also z.B. so etwas: https://shop.hak5.org/products/usb-rubber-ducky-deluxe).

Mit einem normalen USB-Stick kannst du lediglich eine autorun.inf erstellen, allerdings wird das inzwischen in fast allen Fällen nicht mehr funktionieren.

...zur Antwort

Hier mal ein kurzes Beispiel für eine von der Punktzahl abhängige Nachricht an den Nutzer:

@echo off
set /p "points=Deine Punktzahl: "
cls

echo.Du hast %points% Punkte erreicht!
if %points% geq 15 (
  echo Sehr gut gemacht!
  goto end
)
if %points% geq 10 (
  echo Ganz gute Leistung.
  goto end
)
if %points% geq 5 (
  echo Naja, das geht besser.
  goto end
)
echo Grottenschlecht.

:end
  echo.Endnachricht oder Frage nach erneutem Spiel oder so hierhin...
  pause
exit

Es gibt aber eine Vielzahl an Möglichkeiten um ein derartiges Verhalten umzusetzen. Was genau hast du denn im Gesamten vor? Dann kann ich dir vielleicht etwas spezifischer helfen :)

...zur Antwort

Was mir zuerst auffällt sind die falschen if-Abfragen: Du hast hier Zahlen vorliegen, da solltest du keinen String-Vergleich durchführen und demnach auch keine Anführungszeichen verwenden. Vor allem aber solltest du nie die Anführungszeichen nur auf einer Seite verwenden, da z.B. `5=="5"` oder auch `16 leq "16"` immer false ist.

Zudem brauchst du keine else-if Verschachtelung, wenn du nur goto's benutzt.

Was aber wahrscheinlich den Fehler verursacht hat, ist das Springen zu Labels, welche nicht existieren. Ich habe dir hier mal eine verbesserte Version aufgeschrieben:

set /a ergebnis=%F1%+%F2%+%F3%+%F4%+%F5%
echo.
echo Deine Punktzahl ist %ergebnis%
echo.

ping localhost -n 3 >nul
if %ergebnis% LEQ  7 goto schlecht
if %ergebnis% LEQ 12 goto besser
if %ergebnis% LEQ 16 goto gut
if %ergebnis% LEQ 20 goto ehrenmann

:schlecht
  echo schlecht
  goto ende

:besser
  echo besser
  goto ende

:gut
  echo gut
  goto ende

:ehrenmann
  echo ehrenmann

echo wie auch immer
...zur Antwort

Mit start /b kannst du eine Art zweiten Thread im gleichen Fenster starten und dort dann eine Sekunde warten. Oder du startest eine zweite Batch minimiert und beendest die erste nach einer Sekunde...

Aber warum so kompliziert, wenn der Befehl den du bereits benutzt schon diese Funktion eingebaut hat?

choice /c abc /t 1 /d c

/t 1 lässt dem Benutzer nur eine Sekunde Zeit eine Auswahl zu treffen. Hier eine genauere Beschreibung aus der Hilfe von choice (choice /?):

/T    Zeitlimit  Bestimmt die Länge der Pause vor der Auswahl
                 in Sekunden. Gültige Wert sind 0 bis 9999.
                 Der Wert 0 bedeutet keine Pause und Verwendung
                 der Standardauswahl.

/D    Auswahl    Bestimmt die Standardauswahl nach nnnn Sekunden.
                 Zeichen müssen im Auswahlsatz durch die Option
                 /C und nnnn mit Option /T festgelegt werden.
...zur Antwort

Ein Skript um bestimmte Dateien zu suchen, habe ich vor kurzem erst für diese Frage hier geschrieben. Das sieht dann ungefähr so aus:

@echo off

:: CONFIG ::
set searchDirectory="C:\User\"
set searchString="test.txt"
:: CONFIG ::

set result="%TEMP%\search_result.txt"
cd /D %searchDirectory%
dir /s /b | findstr %searchString% > %result%

:read
set amount=0
for /f "usebackq tokens=*" %%f in (%result%) do (
    set /a amount += 1
)

if %amount% equ 0 (
    echo Datei wurde nicht gefunden.
    del %result%
    pause & exit /b 1
)
if %amount% gtr 1 (
    echo Mehrere Dateien gefunden.
    echo Druecken Sie eine beliebige Taste um alle gefundenen Dateien angezeigt zu bekommen.
    echo Loeschen Sie dann alle ungewuenschten Zeilen, sodass am Ende nur die zu kopierende Datei in der ersten Zeile steht.
    echo Dann speichern Sie ihre Auswahl mit [Strg] + [s] und schliessen das Fenster.
    pause
    notepad %result%
    goto read
)

set /p file=<%result%
del %result%
echo Gefundene Datei: %file%
pause

Die Funktionalität zum Ersetzen der Datei kannst du entweder schnell selbst am Ende einbauen, oder du erklärst genauer, was getan werden soll.

...zur Antwort

Du kannst in eine Batch nicht einfach eine .jar Datei integrieren. Was du machen könntest, wäre mit der Batch die .java Datei zu schreiben (oder sie ist die java Datei selbst mit dem Batch Code als Kommentar zu Beginn) und diese dann zu kompilieren und zu starten.

Das beste ist in deinem Fall aber ohne Zweifel das verwenden von Programmen wie Launch4j, die für dich die jar Datei in eine exe verpacken.

...zur Antwort

Habe dir mal eben eine kleine Batch hierfür geschrieben. Das eigentliche Suchen der Datei wird dabei so erledigt:

dir /s /b | findstr %searchString%

Das komplette Programm kann dann auch mit mehreren gefundenen Dateien umgehen und erledigt auch das kopieren. Die Parameter im CONFIG-Bereich kannst du je nach deinen Anforderungen anpassen.

@echo off

:: CONFIG ::
set searchDirectory="C:\User\"
set searchString="test.txt"
set outputFolder="D:\output"
:: CONFIG ::

set result="%TEMP%\search_result.txt"
cd /D %searchDirectory%
dir /s /b | findstr %searchString% > %result%

:read
set amount=0
for /f "usebackq tokens=*" %%f in (%result%) do (
    set /a amount += 1
)

if %amount% equ 0 (
    echo Datei wurde nicht gefunden.
    del %result%
    pause & exit /b 1
)
if %amount% gtr 1 (
    echo Mehrere Dateien gefunden.
    echo Druecken Sie eine beliebige Taste um alle gefundenen Dateien angezeigt zu bekommen.
    echo Loeschen Sie dann alle ungewuenschten Zeilen, sodass am Ende nur die zu kopierende Datei in der ersten Zeile steht.
    echo Dann speichern Sie ihre Auswahl mit [Strg] + [s] und schliessen das Fenster.
    pause
    notepad %result%
    goto read
)

set /p file=<%result%
del %result%
cd /D %outputFolder%
copy "%file%"
pause
...zur Antwort

Wie du den Fehler schnell behebst (zurücksetzen von Klick und verwenden von "") wurde ja schon gezeigt. Allerdings ist dies eine gute Stelle um choice zu verwenden.

Knapp formuliert könnte das dann so aussehen:

@echo off
:main
set /p "operand1=Erster  Operand: "
:loop
set /p "operator=Operator (+-/*): "
set /p "operand2=Zweiter Operand: "
set /a operand1 %operator%= operand2
echo:=%operand1%

choice /m "[f]ortfahren oder [n]eu beginnen" /c fn
if errorlevel 2 goto main
if errorlevel 1 goto loop
...zur Antwort

Du kannst auch eine Batch zum Autostart hinzufügen, ohne die Batch selbst modifizieren/herumkopieren zu müssen. Es genügt die ersten 5 Zeilen des folgenden Programms zu deiner Batch hinzuzufügen:

set "REG_PATH_RUN=HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"

REG QUERY %REG_PATH_RUN% /v "%~n0" || (
  REG ADD %REG_PATH_RUN% /v "%~n0" /t REG_SZ /d "%~f0"
)

echo Hello World
pause

"REG QUERY ..." überprüft, ob die Batch sich bereits zum Autostart hinzugefügt hat. Falls nicht, wird der errorlevel 1 zurückgegeben und damit der zweite Befehl "REG ADD ..." ausgeführt.

Startest du die Batch also mit obigen Code eingebaut, so wird sie sich von da an immer automatisch beim hochfahren starten. Sollte angezeigt werden, dass der Zugriff verweigert wird, so musst du die Batch als Administrator ausführen (Rechtsklick auf die .cmd-Datei > "Als Administrator ausführen").

...zur Antwort

Deine Beschreibung des Algorithmus ergibt irgendwie keinen Sinn.

suche nach %x%
ersetze %x% mit Wert von a

Soll ein Vorkommen von %x% in einer Datei durch den Wert von a (also %a%) ersetzt werden, so muss x zu Beginn einen Wert haben ─ sonst kannst du ja nicht danach suchen.

Willst du stattdessen x und y Werte zuweisen um anschließend die obige Zuweisung "set %x%=%y%" auszuführen, so führt der Punkt

ersetze %x% mit Wert von a

dazu, dass stets x=a und der Punkt

ersetze %y% mit Wert von b

dazu, dass stets y=b. Also führst du immer `set %a%=%b%` aus. Noch dazu würde das Vorgehen bei dieser Annahme schon bei

suche nach %x%

scheitern, da x ja noch gar nicht definiert ist.

Valide Vorgehensweisen wären z.B.

  • Ersetze in einer Datei jedes Vorkommen von einem Variablenwert durch den Wert einer anderen Variable.
  • Lese eine Datei aus, die in einem bestimmten Format vorliegt, um Variablen Werte zuzuweisen. Ein Beispiel hierfür könnte sein:

Für eine Datei data.txt mit folgendem Inhaltsschema

a: text1
b: text2

soll für jede Zeile eine Zuweisung der Form `set a=text1` ausgeführt werden.

Was genau soll also nun geschehen?

  • Welche Werte hast du zu Beginn vorliegen?
  • Welche Dateien mit welchem Inhalt möchtest du einlesen?
  • Sollen die Dateien verändert werden?
  • Welche Werte möchtest du nach Durchlauf des Algorithmus vorliegen haben?
...zur Antwort

Für arithmetische Operationen steht dir `set/a` zur Verfügung:

set /a minutes = 5
set /a seconds = minutes * 60

Die Berechnung muss dabei vor dem shutdown-Befehl ausgeführt werden. Dein Beispiel muss also so aussehen:

set /a Wert *= 60
shutdown -s -t %Wert% -f

`set /a Wert *= 60` ist dabei eine Kurzschreibweise für

set /a Wert = Wert * 60

mit der du den Variablennamen nicht zweimal hinschreiben musst.

...zur Antwort

Wenn es sich tatsächlich nur um eine einzige Variable handelt, kannst du das ganz schnell so machen:

Speichern:

echo.%variable%>"save.txt"

Laden:

set /p variable=<"save.txt"

Ein einfaches Beispielprogramm damit könnte so aussehen:

@echo off
set savefile="save.txt"
if not exist %savefile% (
    set /p "variable=What is your name? >"
) else (
    set /p variable=<%savefile%
)

echo Hello %variable%.
echo Confirm your name by pressing [enter] or type a new name:
set /p "variable=>"
echo.%variable%>%savefile%
echo Your name has been stored.
pause

Möchtest du mehrere Variablen speichern und laden, ist es nicht sinnvoll für jede eine eigene Datei und eigene Abfragen sowie Speicher- und Ladebefehle zu schreiben. Stattdessen machst du im Variablennamen deutlich, welche Variablen zu speichern sind und behandelst mehrere auf einmal:

Speichern aller gekennzeichneten Variablen:

>"file" (set "prefix")

Laden aller in einer Datei gespeicherten Variablen:

for /f "usebackq tokens=1* delims==" %%v in ("file") do set "%%v=%%w"

Wieder ein kurzes Beispiel:

@echo off
call :load data
if errorlevel 1 (
    echo Please register:
    set /p "s_firstname=First name: "
    set /p "s_lastname=Last name: "
    set /p "s_age=Your age: "
    echo.
)

echo Welcome %s_firstname% %s_lastname%!
echo Are you still %s_age%?
choice
if errorlevel 2 (
    set /a s_age += 1
    echo Age incremented.
)
call :save s_ * in data
echo Data saved.
pause
exit

:save <prefix> * in <file>
    >"%~4" (set "%~1")
exit /b

:load <file>
    if not exist "%~1" exit /b 1
    for /f "usebackq tokens=1* delims==" %%v in ("%~1") do set "%%v=%%w"
exit /b 0
...zur Antwort

Ja das ist möglich. Wie sieht denn deine Ordnerstruktur aus? Ich gehe mal davon aus, dass das ungefähr so gewollt ist:

Ursprüngliche Struktur:

Desktop
 |- a.png
 |- b.png
 |- unsorted1
     |- c.png
 |- unsorted2
     |- folder
         |- d.png
         |- e.png
 |- sorted
     |- folder01
         |- old1.png
     |- folder02
         |- old2.png

Struktur nach Ausführung der Batch:

Desktop
 |- unsorted1
 |- unsorted2
     |- folder
 |- sorted
     |- folder01
         |- old1.png
         |- a.png
         |- b.png
     |- folder02
         |- old2.png
         |- c.png
         |- d.png
     |- folder03
         |- e.png

Ist das korrekt? Also

  • Dateien die sich bereits im output-Ordner befinden werden ignoriert
  • Alle anderen .png-Dateien im Desktop Ordner und dessen Unterordnern werden nach bestimmten Kriterien in den output-Ordner verschoben.
  • Die ursprüngliche Ordnerstruktur bleibt bestehen.

Zusätzlich wäre noch gut zu wissen, nach welchen Kriterien die Dateien verschoben werden sollen.

...zur Antwort

In Batch hast du neben "==" noch folgende Vergleichsoperatoren zur Verfügung:

    EQU - gleich
    NEQ - nicht gleich
    LSS - kleiner als
    LEQ - kleiner als oder gleich
    GTR - größer als
    GEQ - größer als oder gleich

Also um zwei Zahlen zu vergleichen:

set /a a = 5
set /a b = 7

if %a% leq %b% (
    echo a ist kleiner als oder gleich b
)

Beim Datum allerdings hast du das Problem, dass du meist keine Zahlen, sondern Strings in einem bestimmten Datumsformat vorliegen hast.

Das Datumsformat von %date% kann zudem auf unterschiedlichen Computern variieren. Darum ist es besser das Datum mit z.B. `wmic os get LocalDateTime /VALUE` abzufragen. Das speichern dieses Wertes kannst du mit for erledigen:

for /f "tokens=1,2 delims==" %%d in ('wmic os get LocalDateTime /VALUE') do (if "%%d" equ "LocalDateTime" set dt=%%e)

Da du dich beim Datum nur für die ersten 8 Stellen interessierst, kannst du den Rest abschneiden; Ich füge zudem gerne zwischen Jahr, Monat und Tag noch Striche "-" ein, damit das Datum besser lesbar ist:

set currentDate=%dt:~0,4%-%dt:~4,2%-%dt:~6,2%

Mit `if` kannst du nun einen Stringvergleich mit einem anderen Datum (im selben Format) durchführen:

if "%currentDate%" gtr "%maxDate%" goto licenseExpired

Hier mal ein ganzes Beispielprogramm:

for /f "tokens=1,2 delims==" %%d in ('wmic os get LocalDateTime /VALUE') do (if "%%d" equ "LocalDateTime" set dt=%%e)
::  dateFormat:=   YYYY  -    MM   -   DD
set currentDate=%dt:~0,4%-%dt:~4,2%-%dt:~6,2%
set maxDate=2020-05-10

if "%currentDate%" gtr "%maxDate%" goto licenseExpired

echo passed.
pause&exit

:licenseExpired
echo error. license expired.
pause&exit
...zur Antwort

Alternativ zu "D:" kannst du auch

cd /d D:

verwenden. Der Vorteil davon ist, dass du nicht nur zu einem anderen Laufwerk, sondern auch direkt zu einem Pfad darauf wechseln kannst. Zum Beispiel:

cd /d E:\dies\ist\ein\pfad

Wichtig ist nur, dass du für change directory (cd) die Option /d verwendest, wenn der neue Pfad auf einem anderen Laufwerk liegt.

...zur Antwort