UCS-2 Kodierung und findstr

Dateien können verschiedene Kodierungen haben. Das Kommandozeilen-Werkzeug findstr kann in so einem Fall einen gesuchten String in einer Datei nicht finden. Ich hatte eine Datei, die hatte eine UCS-2 Kodierung und beim Aufruf von

findstr "abc" utc2.txt

kam nichts dabei heraus, obwohl die Textdatei diesen String enthielt. Um den gesuchten String trotzdem zu finden, kann man in so einem Fall auf das SysInternal Tools strings.exe zurückgreifen:

strings -nobanner utc2.txt | findstr "abc"


CreateProcess failed: The system cannot find the file specified.

Beim Bau der Bibliothek skia unter Windows bekam ich diese Fehlermeldung:

[419/2871] copy ../../third_party/externals/icu/common/icudtl.dat icudtl.dat
FAILED: icudtl.dat
python .../skia/build/skia/gn/cp.py ../../third_party/externals/icu/common/icudtl.dat icudtl.dat
CreateProcess failed: The system cannot find the file specified.
ninja: fatal: ReadFile: The handle is invalid.

Wie es sich herausgestellt hat, lag das Problem darin, dass ninja versucht hat, Python aufzurufen, Python aber nicht gefunden hat. Genauer gesagt, python.exe.

Um die python.exe aus den depot_tools aufrufen zu können, muss man vorher erstmal das Skript update_depot_tools.bat aufrufen (wenn man das vorher nicht schon getan hat). Danach sollte sich eine python.exe in dem Ordner <some\path>\depot_tools\win_tools-2_7_6_bin\python\bin befinden. Der Pfad kann sich in der Zukunft vermutlich ändern. Jedenfalls war das bei mir der Fall. Diesen Pfad muss man noch in der Umgebungsvariable PATH hinzufügen, z.b. in einem Batch-Skript mit

set "PATH=%PATH%;<some\path>\depot_tools\win_tools-2_7_6_bin\python\bin"

Danach sollte der Fehler verschwunden sein.

Anmerkungen zu if errorlevel 0

Ab und an sieht man im Internet Batch-Code, bei denen es um die Abfrage geht, ob der Errorlevel 0 oder ungleich 0 ist. Dabei sieht man Code-Zeilen, die in etwa so aussehen:

if errorlevel 0 (
...
) else (
...
)

Diese Abfrage ist aber in vielen Fällen falsch. Im Grunde bedeutet sie: Ist der Errorlevel 0 oder größer. D.h. diese Abfrage kommt fast gar nicht in den else-Teil, weil der Errorlevel meist 0 oder größer ist. Außer man hat ein Programm, welches negative Errorlevel zurückgibt.

Wenn man nun aber wissen möchte, ob der Errorlevel 1 oder größer ist, dann muss die Abfrage anders gestaltet werden:

if errorlevel 1 (
...
) else (
...
)

“File not found” beim dir Kommando

Mittels des Kommandos

dir /b "<Pfad>" 

kann man sich die Dateinamen in dem Ordner <Pfad> auflisten lassen. Also nur die Dateinamen, ohne den gesamten Pfadnamen und ohne sonstige Informationen. Nun war die Aufgabe nicht alle Dateinamen aufzulisten, sondern nur jene die eine bestimmte Endung hatten. Versucht habe ich dann erst einmal so:

dir /b "<Pfad>" *.cmd

Ich bekam eine Ausgabe, die mich etwas stutzig gemacht hat:

Woher kam die Meldung File not Found? Wie es sich herausgestellt hat, führt diese Art dir aufzurufen zu folgendem Verhalten: Zuerst werden alle Dateien in dem Ordner <Pfad> aufgelistet und dann alle *.cmd Dateien, die sich in dem Ordner befinden in dem ich mich gerade in der Konsole befinde. Und in diesem Beispiel war das eben der C:\ Ordner. Und weil ich in C:\ keine *.cmd Dateien hatte, hat dir mir die Fehlermeldung File not Found ausgegeben.

Um trotzdem alle Dateinamen mit bestimmter Endung in einem Ordner heraus zu finden, muss man das Kommando nur leicht abändern:

dir /b <Pfad> | findstr /R /C:"\.cmd$"

Mit findstr das letzte Zeichen prüfen

Mit dem Kommandowerkzeug findstr kann man unter Windows auf das letzte Zeichen eines Strings überprüfen. Eine Art dies zu bewerkstelligen kann man an folgendem Code sehen. Hier wird geprüft, ob die Variable %Project% mit einem Schrägstrich / endet oder nicht. Dabei wird ein Regex verwendet. Das Dollarzeichen in dem Regex steht hier für das Zeilenende, daher auch der “/$”:

@ECHO OFF
SETLOCAL EnableDelayedExpansion
SET "Project=/Folder1"
ECHO %Project%| findstr /R /C:"/$" 1>nul
echo %ERRORLEVEL%

SET "Project=/Folder1/"
ECHO %Project%| findstr /R /C:"/$" 1>nul
echo %ERRORLEVEL%

Bei diesem Code sollte man beachten, dass es kein Leerzeichen zwischen der Variablen %Project% und dem Pipelinezeichen | gibt. Gibt es ein Leerzeichen wird der gesamte Befehl missinterpretiert als würde das letzte Zeichen des Strings ein Leerzeichen sein und findstr gibt dann in beiden Fällen eine 1 zurück.

findstr Beispiel: Bestimmte Zeilen ausschließen

Manchmal muss man mit Hilfe des Tools findstr bestimmte Zeilen ausschließen aus einer langen Liste von Daten. Dies will ich hier an einem kleinen Beispiel zeigen. Angenommen, man hat eine Liste an Zeilen wie diese hier:

(TR3919) Power '1' has been deployed to version '1'
(TR9102) Power '2' has NOT been deployed to version '2'
Random text and 13773r5, with a big error…
(TR1337) complicated
(TR1239) error

Und nun möchte man alle Zeilen bekommen, die entweder mit (TRXXXX) anfangen (wobei XXXX eine Zahl zwischen 0000 und 9999 sein kann) oder die ein error enthalten. Zeilen, die ein has been deployed enthalten, sollten rausgefiltert werden. Das kann man mit folgendem Befehl erreichen:

findstr "(TR[0-9][0-9][0-9][0-9]) error" "data1.txt" | findstr /V /C:"has been deployed"

Der erste findstr-Befehl sucht alle Zeilen heraus, die ein (TRXXXX) oder ein error enthalten. Nun muss man noch die Zeilen herausfiltern, die ein has been deployed enthalten und das erreicht man mit Hilfe des zweiten findstr-Befehls.

Der Parameter /V dient dazu, all jene Zeilen zu finden, die den angegeben String nicht enthalten. Der Parameter /C gibt an, dass nach genau diesem String, also Zeichen für Zeichen genau, gesucht wird. Bzw. in diesem Fall soll also genau dieser String nicht dabei sein (eben wegen dem Parameter /V).