Python - boards.local.txt vollautomatisch erstellen

Hallo,

ich habe mich einmal mit Python beschäftigt und ein Pythonscript erstellt zur Modifizierung der boards.txt im Core Package Ordner. Für mich für ESP32 Boards. Verwendet mit Arduino IDE 2.x, sollte auch mit 1.x funktionieren. In letzter Zeit gab es häufig von Espressif Core Package Updates und damit war immer eine Änderung für die boards.local.txt notwendig. Das ist hiermit vollautomatisiert. :slight_smile:
Die boards.txt wird nur lesend behandelt.
Alle Änderungen werden in die boards.local.txt geschrieben, die mit jeder Scriptausführung neu erstellt wird.
Man muss im Script den Pfad zur boards.txt angeben.
Und man gibt den/die Boardnamen an, die automatisch auskommentiert werden sollen, sodass nur diese in der Auswahl erscheinen. Hierfür muss die volle Bezeichnung einmalig rausgesucht werden, weil kürzere Angaben mehrfach in der boards.txt vorkommen. Ich habe versucht es verständlich zu kommentieren.

Quellcode
# https://forum.arduino.cc/t/boards-local-txt-vollautomatisch-erstellen/1373353

import os
import re

# Pfad zum Core Package definieren
pathDir: str = r"C:\Users\Worker\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0"

# Boards zur Verwendung definieren, die man im Auswahlmenü sehen möchte
boardNames = ['XIAO_ESP32S3.hide=true', 'XIAO_ESP32S3_Plus.hide=true', 'nano_nora.hide=true']  

def modifiziereDatei(regAusdruck, quellDatei, zielDatei):
    
    pathFileRead  = os.sep.join([pathDir, quellDatei])
    pathFileWrite = os.sep.join([pathDir, zielDatei])
    
    fileRead  = open(pathFileRead,  "r")   
    fileWrite = open(pathFileWrite, "w")
    dataLine = fileRead.readlines()
    
    for zeile in dataLine:
        if regAusdruck in zeile:
            # jeweilige Kopfzeile erzeugen
            # Teile der Zeile nach dem 'regAusdruck' behalten
            tempLineA = zeile.split(regAusdruck,1)[1]
            fileWrite.write("# ")
            fileWrite.write(tempLineA)
            #print("#", tempLineA)    # Debug
            
            # ab hier dazugehörige Menüzeile erzeugen
            # Nur den Teil bis zum 'regAusdruck' ausgeben und den 'regAusdruck' ersetzen
            tempLineB = (zeile.split(regAusdruck)[0] + ".hide=true") 
            
            # Suche nach kompletter Übereinstimmung mit einem 'BoardNames' Eintrag
            # Wenn es übereinstimmt, schreibe ein '#' davor in diese Zeile' 
            gefundeneBoards = []                   # Debug
            if any(re.fullmatch(m, tempLineB) for m in boardNames):
                gefundeneBoards.append(tempLineB)  # Debug
                print(gefundeneBoards)             # Debug
                fileWrite.write("# ")  
                
            #print(tempLineB)             # Debug        
            fileWrite.write(tempLineB)
            fileWrite.write("\n\n")
            
    fileWrite.close()  
    fileRead.close()    

#                  Ausdruck  Read          Write        
modifiziereDatei(".name=", "boards.txt", "boards.local.txt")
Script

SuchenErsetzen_v1.1.0.zip (1,0 KB)

Edit:
Ggf. wichtig, verwendete derzeit aktuelle Pythonversion 3.13.

5 Likes

Interessant!

Kann zwar nicht mit Python umgehen...
Finde die Idee allerdings Klasse!

nice.

minor:
sollte da nicht stehen, dass man mit hide=true angibt, welche Boards NICHT angezeigt werden sollen?

Hallo,

Danke Euch.

Ähm ne das passt schon. Das die negative Logik verwirrt hatte ich befürchtet. Das liegt am Aufbau und Verwendung der boards.txt. Ich weiß wie du das meinst, jeder liest das anders, vertraue einfach meinem Kommentar. :wink:

Die Einträge in der boardNames[] Liste sollen nicht versteckt werden. Diese Einträge werden am Ende auskommentiert. Das sind nur Vergleichsmuster/Suchmuster. Mit diesen Einträgen wird jede erzeugte Zeile 'tempLineB' verglichen und bei einem kompletten Treffer mittels '#' auskommentiert. Ich vergleiche erst nach Erstellung der endgültigen Zeile, bevor sie in die boards.local.txt geschrieben wird. Ich kann bspw. nicht nur nach 'esp32s3' suchen und vergleichen, weil es mehrere Boardeinträge in der boards.txt gibt die diesen String enthalten. Damit würde man mehrere Boards ungewollt auskommentieren und damit im Menü sichtbar machen. Deswegen habe ich mich für 'fullmatch' entschieden und muss die bis dahin erzeugte Bezeichnung/Zeile für den Vergleich komplett angeben.

Ich habe es mir einfach gemacht und nicht nochmal angefangen ein 'hide=true' während der Erzeugung anzuhängen. Vielleicht kann man das noch besser gestalten. 'hide=false' habe ich noch nicht probiert.

Das Script automatisiert erstmal "nur" was ich von Hand bzw. mit Notepad++ halbautomatisch bis jetzt gemacht habe. Mit PowerShell hatte ich auch rumgespielt, aber das ist doch eine andere Nummer und für andere OS nicht verfügbar.

Das PowerShell Script sieht so aus, dafür hatte ich fremde Hilfe. Hier fehlt noch die Auskommentierung. Ist äußert kompakt nur leider für mich auf Dauer schwer lesbar.

Get-Content boards.txt | ForEach-Object {
    if ($_ -match "^(.*?\.name)=(.*)$") {
        "# $($matches[2])"
        $($matches[1]).Replace('.name','.hide=true')
    }
} | Set-Content boards.local.txt

Vielleicht überarbeite ich das Pythonscript nochmal. Mal sehen. :thinking: Aktuell macht es seinen Job. :face_with_monocle:

Ich muss da gerade an eine PHP Version denken.
Auf einem öffentlichen Server ist es dann für jeden sofort verfügbar

Könnte ich gut gebrauchen, leider bekomme ich eine Fehlermeldung (Win10, ".py" mit Python 2.7.17 verknüpft):

f:\Arduino\Internet>SuchenErsetzen_v1.1.0.py
  File "F:\Arduino\Internet\SuchenErsetzen_v1.1.0.py", line 7
    pathDir: str = r"C:\Users\Worker\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0"
           ^
SyntaxError: invalid syntax

Ist meine Version zu alt?

Ja, aber erst seit knapp 5 Jahren :slight_smile:
https://de.wikipedia.org/wiki/Python_(Programmiersprache)#Ende_von_Python_2

2 Likes

Hallo,

Server habe ich keinen. :roll_eyes:

Meine Pythonversion ist die aktuelle 3.13. Zwischen 2.x und 3.x gab es größere Änderungen.
Wenn du gute Gründe für 2.x hast, müßtest du einmal googeln wie man eine Pfadvariable erstellt. Ansonsten solltest du aktualisieren. In der Softwareentwicklung stehen bleiben ist nie eine gute Idee. Man kann sich auch mehrere Pythonversionen installieren. Ob das den Aufwand wert ist kann ich nicht sagen. Ich versuche immer aktuell zu bleiben.

Probieren kannst du

pfad = "C:\Users\Worker\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0"
print(pfad)

Oder Platformübergreifend

import os

pfad = os.path.join("C:\Users\Worker\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0")
print(pfad)

Den Pfad selbst hast du aber an deinen Rechner angepasst?

1 Like

Ach schau an, da habe ich doch praktisch nichts versäumt :zany_face:

Danke, das wollte ich wissen :slightly_smiling_face:

Ich habe heute das erste Mal bewußt ein Python-Script gestartet. Wußte nicht, daß das installiert ist. Nach Update auf 3.13.3 läuft Dein Script, wie es soll!

Danke, kann ich gut verwenden!

Bei "esp32s3.hide=true" ist "true" wohl ohne Funktion, denn "false" macht keinen Unterschied. Bisher hatte ich es etwas kompakter:

esp32s2.hide=		# ESP32S2 Dev Module
#esp32.hide=		# ESP32 Dev Module 

Mal schauen, ob ich das umgebastelt bekomme :thinking:

das ist nur bei IDE 1.8.x so! 2.x braucht explizit true oder false!

2 Likes

Danke, dann lasse ich das natürlich drin!

Hallo,

eine auskommentierte Zeile mittels # funktioniert mit IDE 1.9 und 2.x.
# esp32c3.hide=true

Mit Arduino IDE 2.x funktioniert = false, soeben ausprobiert, jedoch mit IDE 1.9 nicht getestet.
esp32c3.hide=false
Ich überlege im Moment das Script doch noch zu überarbeiten.

@agmue
hide= war schon immer negative Logik. Wer sich das ausgedacht hat ... wir können es nicht mehr ändern.

Ich war es nicht :innocent:

Hallo,

ich habe es nochmal überarbeitet. Damit werden auch die Listeneinträge am Anfang in Zeile 10 kürzer, weil der Zusatz '.hide=true' wegfällt. Die weitere Stringverkettung erfolgt Fall abhängig je nach Übereinstimmung.
Es sind beide Varianten enthalten zur Sichtbarkeit im IDE Menü.

# esp32c3.hide=true
esp32c3.hide=false

Wobei letztere Variante nur Sinn macht, wenn man nur noch die IDE 2.x verwendet.
Deswegen ist diese Verkettung im Script auskommentiert.

Quellcode
# https://forum.arduino.cc/t/boards-local-txt-vollautomatisch-erstellen/1373353

import os
import re

# Pfad zum Core Package definieren
pathDir: str = r"C:\Users\Worker\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0"

# Boards zur Verwendung definieren, die man im Auswahlmenü sehen möchte
boardNames = ['XIAO_ESP32S3', 'XIAO_ESP32S3_Plus', 'nano_nora']  

def modifiziereDatei(regAusdruck, quellDatei, zielDatei):
    
    pathFileRead  = os.sep.join([pathDir, quellDatei])
    pathFileWrite = os.sep.join([pathDir, zielDatei])
    
    fileRead  = open(pathFileRead,  "r")   
    fileWrite = open(pathFileWrite, "w")
    dataLine = fileRead.readlines()
    
    for zeile in dataLine:
        if regAusdruck in zeile:
            # jeweilige Kopfzeile erzeugen
            # Teile der Zeile nach dem 'regAusdruck' behalten
            tempLineA = zeile.split(regAusdruck,1)[1]
            fileWrite.write("# ")
            fileWrite.write(tempLineA)
            #print("#", tempLineA)    # Debug
            
            # ab hier dazugehörige Menüzeile erzeugen
            # Nur den Teil bis zum 'regAusdruck' ausgeben und den 'regAusdruck' ersetzen
            tempLineB = (zeile.split(regAusdruck)[0]) 
            #print(tempLineB)             # Debug    
              
            # Suche nach kompletter Übereinstimmung mit einem 'BoardNames' Eintrag
            # Wenn es übereinstimmt, hänge ein '.hide=false' dahinter bzw. '#' davor, wenn nicht '.hide=true' 
            gefundeneBoards = []                   # Debug
            fertigeZeile = []
            
            if any(re.fullmatch(m, tempLineB) for m in boardNames):
                gefundeneBoards.append(tempLineB)  # Debug
                #print(gefundeneBoards)            # Debug
                # --------------------------------------------------
                # ### nur für Arduino IDE 2.x ######################
                #fertigeZeile = (tempLineB + ".hide=false")
                # --------------------------------------------------
                # ### für Arduino IDE 1.9.x und IDE 2.x ############
                fertigeZeile = ("# " + tempLineB + ".hide=true")
                # --------------------------------------------------
                print(fertigeZeile)             # Debug     
            else: fertigeZeile = (tempLineB + ".hide=true")
                
            #print(fertigeZeile)             # Debug        
            fileWrite.write(fertigeZeile)
            fileWrite.write("\n\n")
            
    fileWrite.close()  
    fileRead.close()    

#                  Ausdruck  Read          Write        
modifiziereDatei(".name=", "boards.txt", "boards.local.txt")

Script

SuchenErsetzen_v1.1.1.zip (1,1 KB)

Ich denke dabei kann ich es belassen.

1 Like

Dieses Python-Paket könnte für Sie hilfreich sein:

Es unterstützt die Arbeit mit dem Arduino-Datenformat „properties“ der Dateien boards.txt und boards.local.txt.

Es wurde von einem Arduino-Forum-Mitglied erstellt: @jfjlaros

Hallo,

ich konnte es nicht sein lassen. Jetzt machen wir es richtig oder gar nicht. :joy: Version 1.2.0. Ist auch Spielwiese für mich. Die meisten verwenden mehrere Controller-Architekturen, wie ich auch, also musste ein Auswahlmenü her. Ich wurde hier Lysander Menü Snippets fündig wie man sowas erstellt. Sehr interessant zum Lesen. Tja und dann sollte noch ein Backup vorm Überschreiben her. Wer weiß wofür das gut ist. :thinking:

Den gemeinsamen Pfad für die Backups gibt man in Zeile 28 an.
Der Dateiname boards.local.txt, falls schon vorhanden, wird um Datum und Uhrzeit modifiziert und in den Backup Ordner kopiert.

Mit der copy2 Methode werden die Metadaten der Datei beibehalten. Der neue Dateiname vom Backup erhält den aktuellen Zeitstempel im Namen, aber Windows zeigt in der Spalte "Änderungsdatum" noch das alte originale Datum an, an dem die Datei damals erstellt/geändert wurde. Wer das nicht möchte ändert copy2 auf copy. Findet man in der Funktion erstelleBackup().

Wenn man zu erstellende .txt von Cores Packages löschen oder hinzufügen möchte, dann löscht oder legt man neue pathDir... und boardNames... Definitionen an. Zeilen 12 bis 26.

Dazu passende Funktion boards… erstellen. Zeilen 114 bis 154.

Danach noch das Menü entsprechend anpassen mit Anzeige und Funktionsnamen. Zeile 209 bis 215.

Ich denke damit ist erstmal Schluß. :joy:

Quellcode
# https://forum.arduino.cc/t/boards-local-txt-vollautomatisch-erstellen/1373353
# Code für das Auswahlmenü von https://github.com/Lysander/snippets

import sys
import shutil
import os
import re
from datetime import datetime

# --- Benutzer Definitionen --------------------------------------------------------------------------------

# Pfade zum Core Packages definieren
pathDirAVR: str       = r"G:\Arduino IDE Portable\Mega2560_stdCpp2\arduino-1.8.19\portable\packages\arduino\hardware\avr\1.8.6"
pathDirDxCore: str    = r"G:\Arduino IDE Portable\AVRxDB\arduino-1.8.19\portable\packages\DxCore\hardware\megaavr\1.5.11"
pathDirMegaAVR: str   = r"G:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\packages\arduino\hardware\megaavr\1.8.8"
pathDirMegaCoreX: str = r"G:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\packages\MegaCoreX\hardware\megaavr\1.1.2"
pathDirESP32: str     = r"C:\Users\Worker\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0"
pathDirESP8266: str   = r"C:\Users\Worker\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2"

# Boards zur Verwendung definieren, die man im Auswahlmenü sehen möchte
boardNamesAVR       = ['uno', 'mega']  
boardNamesDxCore    = ['avrdb', 'avrdbopti'] 
boardNamesMegaAVR   = ['nona4809']             # Arduino megaavr - Nano Every
boardNamesMegaCoreX = ['4809']                 # MCUdude MegaCoreX
boardNamesESP32     = ['XIAO_ESP32S3', 'XIAO_ESP32S3_Plus', 'nano_nora'] 
boardNamesESP8266   = ['d1'] 

pathDirBackup: str = r"C:\Users\Worker\Documents"

# --- Ende der Benutzer Definitionen ------------------------------------------------------------------------

ZIELDATEI = "boards.local.txt"
QUELLDATEI = "boards.txt"

# --- Hilfsfunktionen ---------------------------------------------------------------------------------------

def getDatumUhrzeit():
    # aktuelles Datum und Uhrzeit zusammenbauen
    zeitstempel = datetime.now().strftime("%Y%m%d_%H%M%S")
    print("Zeitstempel: ", zeitstempel)     # Debug
    return zeitstempel

def modifiziereBackupName(suffix):
    dateiname, dateiendung = os.path.splitext(ZIELDATEI)
    #print("Dateiname: ", dateiname)         # Debug
    #print("Dateiendung: ", dateiendung)     # Debug
    neuerDateiname = f"{dateiname}_{suffix}_{getDatumUhrzeit()}{dateiendung}"
    #print("neuer Dateiname: ", neuerDateiname)  # Debug
    return neuerDateiname  
      
def erstelleBackup(quellPfad, zielPfad, suffix):
    if os.path.exists(quellPfad):
        neuerBackupPfad = os.path.join(zielPfad, modifiziereBackupName(suffix))    
        shutil.copy2(quellPfad, neuerBackupPfad)    # copy2 behält die Metadaten der Datei
        print(f"Backup im Pfad: {neuerBackupPfad} angelegt.")
    else:
        print(f'Die Datei {quellPfad} existiert (noch) nicht.')
        print("Es wurde kein Backup angelegt.")

#                    Ausdruck     Read        Write     
def modifiziereDatei(regAusdruck, quellDatei, zielDatei, pathDirCore, boardNames):
    
    pathFileRead  = os.sep.join([pathDirCore, quellDatei])
    pathFileWrite = os.sep.join([pathDirCore, zielDatei])
    
    fileRead  = open(pathFileRead,  "r")   
    fileWrite = open(pathFileWrite, "w")
    dataLine = fileRead.readlines()
    
    for zeile in dataLine:
        if regAusdruck in zeile:
            # jeweilige Kopfzeile erzeugen
            # Teile der Zeile nach dem 'regAusdruck' behalten
            tempLineA = ("# " + zeile.split(regAusdruck,1)[1])
            fileWrite.write(tempLineA)
            #print("tempLineA:", tempLineA)     # Debug
            
            # ab hier dazugehörige Menüzeile erzeugen
            # Nur den Teil bis zum 'regAusdruck' ausgeben und den 'regAusdruck' ersetzen
            tempLineB = (zeile.split(regAusdruck)[0]) 
            #print("tempLineB: ", tempLineB)    # Debug    
              
            # Suche nach kompletter Übereinstimmung mit einem 'BoardNames' Eintrag
            # Wenn es übereinstimmt, in IDE Version Abhänggkeit ... 
            # IDE 2.x: '.hide=false' dahinter
            # IDE 1.9: '#' davor & '.hide=true' dahinter (ist zu beiden IDEs kompatibel)
            # ansonsten ohne Übereinstimmung: hänge nur '.hide=true' dahinter
            meineBoards = []                   # Debug
            fertigeZeile = []
            
            if any(re.fullmatch(m, tempLineB) for m in boardNames):
                meineBoards.append(tempLineB)  # Debug
                #print("meineBoards:", meineBoards)         # Debug
                # --------------------------------------------------
                # ### nur für Arduino IDE 2.x ######################
                #fertigeZeile = (tempLineB + ".hide=false")
                # --------------------------------------------------
                # ### für Arduino IDE 1.9.x und IDE 2.x ############
                fertigeZeile = ("# " + tempLineB + ".hide=true")
                # --------------------------------------------------
                #print("meine Boards: ", fertigeZeile)       # Debug - Board Übereinstimmung     
            else: fertigeZeile = (tempLineB + ".hide=true")
                
            #print(fertigeZeile)                    # finales Debug - Was wird geschrieben?
            fileWrite.write(fertigeZeile)
            fileWrite.write("\n\n")
            
    fileWrite.close()  
    fileRead.close()    
    print(f'Die Datei {ZIELDATEI} wurde in {pathDirCore} neu erstellt.')

# --- Funktionen die von der Menüauswahl aufgerufen werden --------------------------------------------------

def boardsAVR():
    SUFFIX = "AVR"
    print(SUFFIX)
    pathQuelle = os.path.join(pathDirAVR, ZIELDATEI)    
    erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)     
    modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirAVR, boardNamesAVR)

def boardsDxCore():
    SUFFIX = "DxCore"
    print(SUFFIX)
    pathQuelle = os.path.join(pathDirDxCore, ZIELDATEI)    
    erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)    
    modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirDxCore, boardNamesDxCore)
    
def boardsMegaAVR():
    SUFFIX = "MegaAVR"
    print(SUFFIX)
    pathQuelle = os.path.join(pathDirMegaAVR, ZIELDATEI)    
    erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)  
    modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirMegaAVR, boardNamesMegaAVR)
        
def boardsMegaCoreX():
    SUFFIX = "MegaCoreX"
    print(SUFFIX)
    pathQuelle = os.path.join(pathDirMegaCoreX, ZIELDATEI)    
    erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)  
    modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirMegaCoreX, boardNamesMegaCoreX)
    
def boardsESP32():
    SUFFIX = "ESP32"
    print(SUFFIX)
    pathQuelle = os.path.join(pathDirESP32, ZIELDATEI)    
    erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)  
    modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirESP32, boardNamesESP32)
    
def boardsESP8266():
    SUFFIX = "ESP8266"
    print(SUFFIX)
    pathQuelle = os.path.join(pathDirESP8266, ZIELDATEI)    
    erstelleBackup(pathQuelle, pathDirBackup, SUFFIX)  
    modifiziereDatei(".name=", QUELLDATEI, ZIELDATEI, pathDirESP8266, boardNamesESP8266)

# --- Menü --------------------------------------------------------------------------------------------------
#
# Core functions of our simple menu system
#
    
def print_menu(menu):
    """
    Function that prints our menu items. It adds an numeric index to each
    item in order to make that the choosebale index for the user.
    
    :param menu: tuple with menu definition
    """
    print()     # Leerzeile vor dem Menü erzeugen
    for index, item in enumerate(menu, 1):
        print("{}  {}".format(index, item[0]))
 
def get_user_input(menu):
    """
    This function implements a simple user input with validation. As the
    input data should match with existing menu items, we check, if the value
    is valid.

    :param menu: tuple with menu definition
    
    :returns: int
    """
    while True:
        try:
            choice = int(input("Deine Wahl? Nummer?: ")) - 1
            if 0 <= choice < len(menu):
                return choice
            else:
                raise IndexError
        except (ValueError, IndexError):
            print("Bitte nur Zahlen aus dem Bereich 1 - {} eingeben".format(
                                                                    len(menu)))

def handle_menu(menu):
    """
    Core function of our menu system. It handles the complete process of
    printing the menu, getting the user input and calling the corresponding
    function.
    
    :param menu: tuple with menu definition
    """
    while True:
        print_menu(menu)
        choice = get_user_input(menu)
        menu[choice][1]()

def main():
    # Auswahlmenü:
    menu = (
        ("AVR", boardsAVR),
        ("DxCore", boardsDxCore),
        ("MegaAVR", boardsMegaAVR),
        ("MegaCoreX", boardsMegaCoreX),
        ("ESP32", boardsESP32),
        ("ESP8266", boardsESP8266),
        ("Exit", lambda: sys.exit(0))
    )
    
    # run the menu-"handler" :-)
    handle_menu(menu)


if __name__ == "__main__":
    main()
Script

SuchenErsetzen_v1.2.0.zip (2,9 KB)

1 Like

Ist ein Windowsding - schon seit Ewigkeiten. Das wird auch nicht mehr geändert.

Das gehört ja auch zu den beizubehaltenden Metadaten.

Gruß Tommy

Hallo,

Ich glaube hier gibt es ein Missverständnis. Wenn man unter Windows Ordner normal kopiert, erhalten diese ein neues/aktuelles Datum. Eigentlich möchte man das meistens nicht im Hinblick auf Backups. copy2 sorgt bewusst dafür, dass das alte Datum erhalten bleibt.

Vielleicht habe ich mich umständlich ausgedrückt. Ich wollte darauf hinweisen, nicht das sich jemand wundert, das im Dateinamen der aktuelle Zeitstempel drin ist und im Dateimanager noch der alte Zeitstempel erscheint. copy2 hatte ich bewusst ausgewählt. Genau weil ich die Metadaten erhalten wollte, weil ich oft nach Datum sortiere und suche.
Ähnlich mit 'T' von robocopy /COPY:DAT /DCOPY:DAT

Hallo,

das Script konvertiert Dateiformate? Mir sind .yaml Dateien nicht bekannt. Ich filtere den Inhalt der boards.txt und schreibe wenige Zeilen modifiziert in die boards.local.txt. Ich ändere nichts an der allgemeinen Formatierung. Die enthaltenen Funktionen und deren Aufbau sind dennoch interessant. Also wie man etwas macht.