Intelligente Lösungen
in neuer Dimension

CUT: Probleme mit UTF-8-Dateien

Gelegentlich verwende ich das Kommando cut, um aus Dateien oder Programmausgaben gewisse Komponenten auszuschneiden und dann weiterzuverwenden.

Leider stellt sich heraus, dass die Option “-c” Probleme mit UTF-8-Dateien hat!

TLDR: Die aktuelle Version von GNU-CUT behandelt “-c” genauso wie “-b”. Getestet mit Ubuntu-20.04.

Ein einfaches Beispiel

Ich habe diese Datei:

1
2
3
4
5
0        1         2
1234567890123456789012
ROT-1  ROT-2  ROT-3
GRÜN-1 GRÜN-2 GRÜN-3
BLAU-1 BLAU-2 BLAU-3

Aus dieser Datei möchte ich die Spalten 08 bis 13 ausscheiden und das mache ich mit cut -c8-13 <dateiname.

1
2
3
4
5
$ cut -c8-13 <dateiname
  1   
890123
ROT-2 
BLAU-2

Das Ergebnis entspricht den Erwartungen

Gleiche Datei “in Grün”

Hier der gleiche Ablauf mit einer leicht modifizierten Datei:

1
2
3
4
5
0        1         2
1234567890123456789012
ROT-1  ROT-2  ROT-3
BLAU-1 BLAU-2 BLAU-3
GRÜN-1 GRÜN-2 GRÜN-3

Es ist lediglich die Zeile mit “GRÜN” dazugekommen. Erwarten würde ich Ausgaben wie diese:

1
2
3
4
5
6
$ cut -c8-13 <dateiname
  1   
890123
ROT-2 
BLAU-2
GRÜN-2

Das reale Ergebnis unter Ubuntu-20.04 sieht so aus:

1
2
3
4
5
6
$ cut -c8-13 <dateiname
  1   
890123
ROT-2 
BLAU-2
 GRÜN

Es fällt auf, dass statt “GRÜN-2” die Zeichenkette “ GRÜN” ausgegeben wird. Scheinbar verhält sich cut -c8-13 ... genauso wie cut -b8-13 ....

Recherchen

Via Google habe ich diese beiden Stellen gefunden:

Daraus geht hervor, dass für GNU-CUT die Optionen “-c” und “-b” gleichartig funktionieren. Das erklärt, warum auch die Ergebnisse/Ausgaben gleichartig sind!

Test mit “uutils/coreutils”

uutils coreutils enthält eine Neuimplementierung von CUT. Ich teste wie folgt:

  • Auschecken: git clone git@github.com:uutils/coreutils.git
  • Wechseln in’s Verzeichnis: cd coreutils
  • Bauen: cargo build
  • Ausführen: target/release/cut -h –> Hilfeseite

Test mit der Datei von oben:

1
2
3
4
5
6
$ target/release/cut -c8-13 <dateiname
  1   
890123
ROT-2 
BLAU-2
 GRÜN

Gleiches Verhalten wie bei GNU-CUT! Kurzsichtung des Quelltextes zeigt, dass es eine Methode “cut_bytes” gibt aber keine Methode “cut_characters” (oder so ähnlich). Also Vermutung: “-c” wurde nicht richtig implementiert!

Notbehelf mit BASH

Mit der BASH kann das gewünschte Verhalten von CUT einfach mit Bordmitteln nachprogrammiert werden:

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

FROM=$1
TO=$2

BASH_FROM="$(expr "${FROM}" - 1)"
BASH_LENGTH="$(expr "${TO}" - "${BASH_FROM}")"
while read line; do
  echo "${line:${BASH_FROM}:${BASH_LENGTH}}"
done

Das Skript speichere ich unter dem Namen “bash-cut.sh” und mache es ausführbar mit chmod +x bash-cut.sh. Damit sieht Ausgabe dann so aus:

1
2
3
4
5
6
$ ./bash-cut.sh 8 13 <dateiname
  1   
890123
ROT-2 
BLAU-2
GRÜN-2

Der Notbehelf funktioniert also!

Links

Änderungen

  • 2022-01-10: Erste Version