• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

[Gelöst] bash-Script, um viele Dateien automatisch zu verlinken

abgdf

Guru
Wobei ich mir gerade mit dem Satz nicht ganz sicher war. Das Aufrufen eines Programms dürfte ja ein Zusammenspiel von Shell, Prozess-Steuerung ("ps xa") und Programm sein. Kann sein, daß die Shell dem Programm die Arbeit mit dem Unicode abnimmt (vielleicht weiß da jemand anderes Genaueres, das sind ja schon wirklich Interna (daher "Grenze des Machbaren")).
Aber vorsichtig mit Unicode in Dateinamen zu sein, ist in jedem Fall richtig.
 
OP
Christina

Christina

Moderator
Teammitglied
Ups! Jetzt habe ich gar nicht gesehen, dass du schon geantwortet hattst.
Ich habe meinen letzten Post nochmal geändert und deine Antwort steht auf der Seite 2.
 
abgdf schrieb:
Wobei ich mir gerade mit dem Satz nicht ganz sicher war. Das Aufrufen eines Programms dürfte ja ein Zusammenspiel von Shell, Prozess-Steuerung ("ps xa") und Programm sein. Kann sein, daß die Shell dem Programm die Arbeit mit dem Unicode abnimmt (vielleicht weiß da jemand anderes Genaueres, das sind ja schon wirklich Interna (daher "Grenze des Machbaren")).
Aber vorsichtig mit Unicode in Dateinamen zu sein, ist in jedem Fall richtig.
Alles ist Unicode, auch Dateinamen. Unicode selbst ist keine Kodierung sondern eine Norm zur Darstellung von Zeichen,
die Kodierungen zusammenfasst. Diese können sein UTF-32, UTF-16, UTF-8 und ein paar ISO/IEC Normen.
Linux verwendet Zeichen in Unicode mit Kodierung UTF-8, Windows Unicode UTF-16.

Jede Applikation ist selbst für die Kodierung verantwortlich. Fast alle portable Programme verwenden das iconv library (libiconv)
Die Programmierer vom iconv library liefern auch eine Applikation mit dem Namen iconv.
iconv arbeitet mit diesem iconv-library. Mit iconv kannst du herumexperimentieren, strings oder files in alle Richtungen
konvertieren und beobachten, wie es unter Linux oder Windows interpretiert wird.
Man kann sagen, dass das iconv-library der Motor hinter allen Kodierungen und Konvertierungen dieser Art ist.

Gruß
Gräfin Klara
 

abgdf

Guru
Gräfin Klara schrieb:
Alles ist Unicode, auch Dateinamen. Unicode selbst ist keine Kodierung sondern eine Norm zur Darstellung von Zeichen, die Kodierungen zusammenfasst. Diese können sein UTF-32, UTF-16, UTF-8 und ein paar ISO/IEC Normen.
Linux verwendet Zeichen in Unicode mit Kodierung UTF-8, Windows Unicode UTF-16.
Ah, ok. Ich hatte jetzt UTF-8 synonym zu Unicode verwendet. Das war nicht ganz präzise, Unicode ist der Zeichensatz, UTF-8 (unter Linux) die zugehörige Kodierung. Stimmt schon.

Eigentlich hoffe ich meistens, daß es in Programmen irgendwie gut geht, und beschäftige mich nur damit, wenn es Probleme gibt. ;)
In meinen Python-Programmen hilft meistens:
Code:
text = text.decode("iso-8859-1")
Wenn nicht, hab' ich ein Problem. Irgendwann muß ich das mal systematisch nachlesen, aber ich hab' immer keine große Lust dazu. :eek:ps: Geht wohl Vielen so. Leidiges Thema.
 
OP
Christina

Christina

Moderator
Teammitglied
Gräfin Klara schrieb:
Alle diese von dir erwähnten Sonderzeichen liegen IMMER im UTF-8 EIN Byte Bereich.
Beispiel '?' = Unicode 0x3F entspricht UTF-8 0x3F.
Unicode 0xFF1F (meines Wissens für UTF-8 wäre das 0x00.ef.bc.9f) sind abseitige Sonderzeichen, die in jedem Fall falsch interpretiert werden würden.
Da die von dir gesuchten Zeichen im EIN Byte UTF-8 liegen, kannst du immer:
Code:
# VAR=${VAR//[\/\?:]/}      # entnimmt alle diese Sonderzeichen aus VAR
# VAR=${VAR//[\/\?:]/x}     # ersetzt alle diese Sonderzeichen mit einem 'x'
# VAR=${VAR//\?/}           # entnimmt nur '?'
usw.
Ich habe das jetzt mit <FF0F>, <FF1F> und <FF1A> (Unicode 1.1 – Juni 1993) ausprobiert.
Die Reihe mit <FFxx> gibt es auch in UTF-16 und UCS-2.
https://en.wikipedia.org/wiki/UTF-16; https://upload.wikimedia.org/wikipedia/commons/0/01/Unifont_Full_Map.png

Das ist aber im Link-Script nur Spielerei. Das brauche ich hier gar nicht. Ich wollte einfach ein praktisches Beispiel fürs Ersetzen von einzelnen Zeichen in einer Variablen im bash-Script haben.
Code:
#!/bin/bash

echo -e "Link-Basisname: \c"
read linkbasename
linkbasename=${linkbasename//\///}
linkbasename=${linkbasename//\?/?}
linkbasename=${linkbasename//:/:}
suffix="wav"

nr=1
ls -1 *.$suffix | while read i
do
    ln -s "$i" "$linkbasename-$(printf "%02d" $nr).$suffix"
    echo "$linkbasename-$(printf "%02d" $nr).$suffix -> $i"
    let nr++
done
Nur, wo oder in welchen Fällen würden solche abseitigen Sonderzeichen im Dateinamen Fall falsch interpretiert?
Fällt dir / euch dazu ein Beispiel ein?

Wenn ich im xfce-Terminal die Kodierung von UTF-8 auf ISO-8859-15 umstelle, sind schon die deutschen Umlaute kaputt, klar.
 
abgdf schrieb:
Geht wohl Vielen so. Leidiges Thema.

So kompliziert ist das nicht.

abgdf schrieb:
Eigentlich hoffe ich meistens, daß es in Programmen irgendwie gut geht, und beschäftige mich nur damit, wenn es Probleme gibt. ;)
In meinen Python-Programmen hilft meistens:
Code:
text = text.decode("iso-8859-1")
Zu deiner Kodierung nach iso-8859-1:
Deine Python Zeile mit x.decode("iso-8859-1") dekodiert den Text in einen
ein Byte code, nämlich in die primäre ASCII Tabelle UND in die extended ASCII Tabelle.
Beide Tabellen sind hier zu sehen:

https://www.ascii-code.com/
Die primäre ASCII Tabelle reicht von 0x00 - 0x7F, die extended Tabelle von 0x80 - 0xFF.

Ein bißchen Geschichte:
Seinerzeit hatte jedes Land mit anderen Zeichen als hierzulande, seine eigene ISO Tabelle.
Alle nach dem Prinzip: ein Zeichen ist ein Byte, Bereich von 0x00 - 0xFF und somit 255 Zeichen maximal.

Das konnte so natürlich nicht weitergehen, z.B. wurde das neue Euro Zeichen mit 0x80 in die extended ASCII Tabelle
hineingequetscht, obwohl es dort überhaupt nicht hinpasst. Die Tabelle war voll, kein Platz mehr vorhanden.

Unicode hat sich dann eine Codierung ausgedacht, die ALLE Zeichen, die auf dieser Welt gebraucht werden,
in einer Tabelle vereint. Begonnen haben sie mit UTF-16, das hatte mit Microsoft zu tun, danach
wurde die UTF-8 Tabelle erstellt.

Wie das Ding funktioniert:
Die 8 in UTF-8 steht nicht für die Zeichenlänge, sondern ist ein Hinweis für den Programmierer, ein Textfile
in 8 Bits zu lesen, also Byte für Byte und zwar ausnahmslos. Weil das so ist, konnte die primäre ASCII Tabelle,
also von 0x00 - 0x7F, 1 zu 1 in die UTF-8 Tabelle übernommen werden. Die extended ASCII Tabelle konnte nicht
integriert werden, Warum? das wirst du bald verstehen

@Christina hat ein Seite über UTF-8 gefunden, wo man das sehen kann.
https://www.utf8-chartable.de/

Ganz links die Angabe zu Unicode ist uninteressant, uns interessiert nur die Spalte UTF-8.
Beginnend von 0x00 - 0x7F findest du die primäre ASCII Tabelle wieder. Ein Byte = ein Zeichen.
Um aber alle Zeichen darstellen zu können, braucht es weit mehr als nur ein Byte je Zeichen.
Nach 0x7F gibt es eine Änderung, dort sieht man 2 Bytes. Wenn der Interpreter - also die Software, die diese
Tabelle in Zeichen übersetzt - auf 0xC2 trifft, dann weiß er, dass er noch ein Byte lesen muß.
Dieses Zeichen ist also 2 Bytes lang, es besteht aus 0xC2 und 0x80. Das Byte 0xC2 nennen wir IB für InformationsByte.

Ein solches IB muß in jedem Fall größer sein als 0x7F, sonst hätte der Interpreter Probleme mit der
ASCII Tabelle am Beginn. Diese IBs ziehen sich durch die gesamte UTF-8 Tabelle und ändern sich natürlich. z.B. fordert 0xE0 zwei
weitere Bytes zu lesen und ab 0xF0 sogar 3 weitere Bytes. Das wäre dann ein Unicode-Zeichen mit einer Größe von 4 Bytes.

Du scheibst:
abgdf schrieb:
Wenn nicht, hab' ich ein Problem.
Natürlich gibt es da ein Problem. Alles im primären Bereich der ASCII Tabelle funktioniert trotz deiner iso-8859-1
Kodierung tadellos unter UTF-8. Befindet sich aber z.B. ein Umlaut im Text, dann wird es problematisch. Ein Ä steht laut iso-8859-1
in der extended ASCII Tabelle. Diese ist in UTF-8 aber nicht integriert. Und es wird noch schlimmer.
Das Ä hat nach iso-8859-1 den hex code 0xC4. Der Interpreter findet das 0xC4, interpretiert es als IB und liest
daraufhin auch noch das nächste byte. Das kann im besten Fall ein völlig falsches Zeichen zur Folge haben,
in den meisten Fällen aber kann er damit nichts anfangen und schon gar nicht darstellen. Somit wird nicht nur
etwas falsches angezeigt, es gehen auch Zeichen verloren. Dem Interpreter kann man das nicht vorwerfen, der
will unter Linux UTF-8 und er geht stur danach vor. Welche Kodierung dem File wirklich zugrundeliegt, das
steht ja nicht als Information im File.

UTF-16 funktioniert genau so, nur steht hier die 16 für "Lies immer 16 Bits" also 2 Bytes.
Deshalb würde dein Problem unter Windows, das ja UTF-16 verwendet, noch viel größer sein.
In die UTF-16 Tabelle kann keine ASCII Tabelle integriert werden, UTF-16 kennt kein Zeichen in Bytegröße,

Wie du siehst, ist das recht einfach und wenn du meinen Text verstanden hast, dann hast du auch Unicode-UTF verstanden.

Gruß
Gräfin Klara
 

abgdf

Guru
Danke für die Ausführungen!

Gräfin Klara schrieb:
Alles im primären Bereich der ASCII Tabelle funktioniert trotz deiner iso-8859-1 Kodierung tadellos unter UTF-8. Befindet sich aber z.B. ein Umlaut im Text, dann wird es problematisch. Ein Ä steht laut iso-8859-1 in der extended ASCII Tabelle. Diese ist in UTF-8 aber nicht integriert. Und es wird noch schlimmer. Das Ä hat nach iso-8859-1 den hex code 0xC4. Der Interpreter findet das 0xC4, interpretiert es als IB und liest daraufhin auch noch das nächste byte. Das kann im besten Fall ein völlig falsches Zeichen zur Folge haben, in den meisten Fällen aber kann er damit nichts anfangen und schon gar nicht darstellen. Somit wird nicht nur
etwas falsches angezeigt, es gehen auch Zeichen verloren. Dem Interpreter kann man das nicht vorwerfen, der will unter Linux UTF-8 und er geht stur danach vor. Welche Kodierung dem File wirklich zugrundeliegt, das steht ja nicht als Information im File.
Also, bei Python 2.7 ist das so: Am Anfang gibt man dem Skript mit, in welcher Kodierung das Skript sein soll. Typischerweise beginnen Python-Skripte daher mit:
Code:
#!/usr/bin/python
# coding: utf-8
Die zweite Zeile ist trotz "#" am Anfang kein bloßer Kommentar, sondern erfüllt eben diese Funktion.
Laut dem hier
https://stackoverflow.com/questions/49991870/python-default-string-encoding
Python 2 reads the source as raw bytes. It only uses the "source encoding" to parse a Unicode literal when it sees one. (It's more complicated than that under the hood but this is the net effect.)
ist es so: Der Datentyp "str" für "normale Strings" ist im Prinzip ASCII. Wenn aber ein Nicht-ASCII-Zeichen im Skript vorkommt, und die "coding"-Zeile oben vorhanden ist, weiß der Python-Interpreter, daß er mit solchen Strings als UTF-8 umgehen soll.
Folgendes funktioniert daher:
Code:
#!/usr/bin/python
# coding: utf-8
a = "Grüße"
print a
print type(a)
Wenn man explizit Unicode-Strings haben will, kann man ein "u" vor dem String verwenden, also
Code:
a = u"Hello"
type ist dann "unicode". Aber das ist irgendwie umständlich und sieht nicht cool aus. Die Zeile
Code:
text = text.decode("iso-8859-1")
wandelt einen String vom Typ "str" nach Typ "unicode".
Wie gesagt ist "str" im Prinzip ASCII, wird manchmal aber auch intern nach UTF-8 (Typ "unicode") gewandelt. Also, dieses geht daher auch:
Code:
#!/usr/bin/python
# coding: utf-8

a = "Grüße"
print type(a)

b = a.decode("iso-8859-1")
print type(b)
Mit Python 3 stehen ich (und viele andere) auf Kriegsfuß und verwende also bis auf weiteres Python 2.7. Aber zu Python 3.8 lese ich, daß das da dann alles nochmal anders ist, und die grundlegende String-Klasse in UTF-8 ist (wogegen ich im Prinzip auch nichts habe, wenn das gut gemacht ist und im Hintergrund abläuft, ohne den Programmierer damit zu nerven).

Python 2.7 macht das also anders als Python 3.8. Und dann gibt es noch bash, Perl, Java und C/C++, die das auch alle verschieden handhaben dürften. Das ist eher das Problem.

Aufgetreten ist das Encoding-Problem in Python bei mir vor allem bei einem kleinen Texteditor (den ich geschrieben hab'). Da wird also Text aus einem Tkinter-Text-Widget gelesen und soll z.B. in eine Text-Datei geschrieben werden. Wenn in dem Text Umlaute sind, reagiert es (bisher) seltsam. (Auch Eingaben aus einem Tkinter-Entry-Widget sollten überprüft werden.) Vielleicht kann ich das Problem ja jetzt lösen. Mal schauen.

Aber ehrlich gesagt: Wenn selbst in der google-gestützten Python-Welt dafür in Version 2.7 keine dauerhafte Lösung gefunden wurde (und wer weiß, ob die Lösung von Python 3.8 endültig ist?), wie sollen dann so kleine Tools wie awk, grep und sed für das UTF-8-Problem eine Lösung haben? Kann ich mir kaum vorstellen.
Ich vermute, in der Shell dürfte man daher große Probleme bekommen, wenn man Texte mit UTF-8-Zeichen verarbeiten will. Aber das kann hier ja mal gern jemand demonstrieren, der die Shell für sowas einsetzt. Empfehlen würde ich das nicht.

Und auch sonst: Sobald es in der Shell Unklarheiten mit Sonderzeichen oder Dateinamen gibt, wechsele ich gleich zu Perl. In diesen Skriptsprachen ist die Stringverarbeitung einfach viel klarer und leistungsfähiger. Da muß man sich auch kaum Gedanken über Leerzeichen im String oder Expandierungen machen. Dadurch wird einfach alles viel einfacher als in der Shell. Und das eigentliche Problem kann schneller gelöst werden. Werden besondere Shell-Befehle benötigt, kann man die einfach mit "system()" aufrufen.
 
abgdf schrieb:
ist es so: Der Datentyp "str" für "normale Strings" ist im Prinzip ASCII. Wenn aber ein Nicht-ASCII-Zeichen im Skript vorkommt, und die "coding"-Zeile oben vorhanden ist, weiß der Python-Interpreter, daß er mit solchen Strings als UTF-8 umgehen soll.
Folgendes funktioniert daher:
Code:
#!/usr/bin/python
# coding: utf-8
a = "Grüße"
print a
print type(a)
Wenn das, so wie du schreibst "auch geht", dann ist das ein Bug in Python.
iso-8859-1 ist ASCII und nichts anderes! Wenn also die Zeilen
b = a.decode("iso-8859-1")
print type(b)
"Grüße" auf das Terminal schreibt, ist die Kodierung in Python 2.7 noch gar nicht wirklich angekommen oder ist unfertig.
Auch die globale Anweisung
# coding: utf-8
ändert nichts an dieser Tatsache. Wenn ich nach iso-8859-1 konvertiere, dann will ich nicht Unicode!

abgdf schrieb:
Python 2.7 macht das also anders als Python 3.8...

Ganz offensichtlich wird an der korrekten Kodierung noch gearbeitet.
Ziemlich verspätet, würde ich meinen.

abgdf schrieb:
Aufgetreten ist das Encoding-Problem in Python bei mir vor allem bei einem kleinen Texteditor (den ich geschrieben hab')...

Es gibt dafür einen einfachen Test. Du würdest dich wundern, wieviele existierende Editoren damit Probleme haben.
Erstelle ein Textfile mit einem Hex Editor und schreibe hinein (in Hex)
31.C3.A3.32.0A

Interpretiere dieses Textfile in ASCII, d.h. iso-8859-1, dann muß in einem Texteditor zu sehen sein 1, A mit tilde, Pfund, 2
1ã2
Interpretiere dieses Textfile in UTF-8, dann muß zu sehen sein 1, a mit tilde, 2
1ã2
Wenn die Darstellung anders aussieht oder sich die Reihenfolge der Zeichen ändert, dann ist das ein Bug.
Dasselbe gilt für alle Browser oder Linux Terminals, die ja auch auf iso-8859-1 oder UTF-8 eingestellt werden können, also z.B.:
# cat textfile

Da gibt es keine Kompromisse und irgendwas dazwischen ist auch falsch.

Gruß
Gräfin Klara
 

abgdf

Guru
Code:
#!/usr/bin/python
# coding: utf-8

h = (0x31, 0xc3, 0xa3, 0x32)
s = ""
for i in h:
    s += chr(i)
print s
print type(s)
print 

s2 = s.decode("iso-8859-1")
print s2
print type(s2)
ergibt:
Code:
1ã2
<type 'str'>

1ã2
<type 'unicode'>
Was für mich mal wieder sehr verwirrend ist.

Python 2.7 ist von 2010, da war Unicode also schon über 15 Jahre bekannt. Wenn ich nicht irre, ist die Google-Suchmaschine in Python (und der Erfinder, Guido van Rossum, arbeitet selbst auch für Google). Man kann also davon ausgehen, daß an der Entwicklung von Python hochbezahlte Profis arbeiten, die sich auskennen (inzwischen ist Google mit unseren Daten schließlich zu einem der reichsten Unternehmen der Welt geworden). Wenn Python 2.7 UTF-8 so behandelt, wie es es tut, dann wird das schon einen Grund haben. Der aber nichts mit mangelnder Kompetenz der Entwickler zu tun hat.
 
abgdf schrieb:
Code:
#!/usr/bin/python
# coding: utf-8

h = (0x31, 0xc3, 0xa3, 0x32)
s = ""
for i in h:
    s += chr(i)
print s
print type(s)
print 

s2 = s.decode("iso-8859-1")
print s2
print type(s2)
ergibt:
Code:
1ã2
<type 'str'>

1ã2
<type 'unicode'>
Was für mich mal wieder sehr verwirrend ist.

Hi

Alle Resultate, so wie sie sich hier in deinem Test darstellen, sind korrekt und deshalb auch einfach zu verstehen.
Den String "0x31, 0xc3, 0xa3, 0x32" habe ich deshalb so gewählt, weil die Kodierung dieses Strings für keinen Interpreter
eruierbar ist. Der String ist ja in ASCII als auch Unicode gültig und korrekt darstellbar, wenn auch mit unterschiedlichen Zeichen.

Interpretation nach Unicode(utf-8):
0x31 = '1'
0xc3.0xa3 = 'ã'
0x32 = '2'

Interpretation nach ASCII (iso-8859-1):
0x31 = '1'
0xc3 = 'Ã' # A mit tilde
0xa3 = '£'
0x32 = '2'

Nach deiner loop das print s
gibt den String 1:1 aus, was ein gültiges Ergebnis in UTF-8 zum Resultat hat:
1ã2
Type von s darf, muß aber nicht unicode sein. Wie schon geschrieben, der String ist gültig für iso UND Unicode.
Würdest du dein Programm in einem Terminal mit Kodierung iso-8859-1 starten, würde an dieser Stelle
1ã2
ausgegeben werden, was in diesem Fall ebenfalls korrekt wäre.

s2 = s.decode("iso-8859-1")
dekodiert diesen string korrekterweise VON iso NACH Unicode (UTF-8).
Das decode ergibt in s2:
0x31 " '1'
0xc3,0x83 = 'Ã' # A mit tilde
0xc2,0xa3 = '£'
0x32 = '2'

Resultat:
1ã2
und type von s2 ist unicode
Alles ok. Es entspricht exakt der Interpretation aller Zeichen und der Zeichenfolge nach iso-8859-1 (siehe oben) und ist somit korrekt.

In einem obigen Beitrag schreibst du:
# coding: utf-8
a = "Grüße"
b = a.decode("iso-8859-1")
print b

ergibt "Grüße".

Dieses Resultat ist und bleibt falsch, der type von a ist in diesem Fall irrelevant, a darf nicht als Unicode interpretiert werden, weil
"iso-8859-1" eine dezidierte Information in einer Anweisung zur geforderten Dekodierung von a ist, die genau so gewollt wird!
Egal ob von Google, hochbezahlter Profis und deren Kompetenz, bug bleibt bug, vorausgesetzt natürlich,
deine Beschreibung entspricht den Tatsachen. Ich habe keine deiner Python Zeilen nachvollzogen.

Gruß
Gräfin Klara
 
Oben