2013-07-03 5 views
9

Das macht mich verrückt. Habe das nächste Bash-Skript.Portable (Cross-Plattform) Scripting mit Unicode-Dateinamen

testdir="./test.$$" 
echo "Creating a testing directory: $testdir" 
mkdir "$testdir" 
cd "$testdir" || exit 1 

echo "Creating a file word.txt with content á.txt" 
echo 'á.txt' > word.txt 

fname=$(cat word.txt) 
echo "The word.txt contains:$fname" 

echo "creating a file $fname with a touch" 
touch $fname 
ls -l 

echo "command: bash cycle" 
while read -r line 
do 
    [[ -e "$line" ]] && echo "$line is a file" 
done < word.txt 

echo "command: find . -name $fname -print" 
find . -name $fname -print 

echo "command: find . -type f -print | grep $fname" 
find . -type f -print | grep "$fname" 

echo "command: find . -type f -print | fgrep -f word.txt" 
find . -type f -print | fgrep -f word.txt 

Auf der Freebsd (und wahrscheinlich auch auf Linux zu) gibt das Ergebnis:

Creating a testing directory: ./test.64511 
Creating a file word.txt with content á.txt 
The word.txt contains:á.txt 
creating a file á.txt with a touch 
total 1 
-rw-r--r-- 1 clt clt 7 3 júl 12:51 word.txt 
-rw-r--r-- 1 clt clt 0 3 júl 12:51 á.txt 
command: bash cycle 
á.txt is a file 
command: find . -name á.txt -print 
./á.txt 
command: find . -type f -print | grep á.txt 
./á.txt 
command: find . -type f -print | fgrep -f word.txt 
./á.txt 

Auch in dem Windows 7 das Skript gibt richtig Ergebnis läuft (mit Cygwin installiert ist).

Aber wenn ich dieses Skript ausführen auf OS X bash, diese bekam:

Creating a testing directory: ./test.32534 
Creating a file word.txt with content á.txt 
The word.txt contains:á.txt 
creating a file á.txt with a touch 
total 8 
-rw-r--r-- 1 clt staff 0 3 júl 13:01 á.txt 
-rw-r--r-- 1 clt staff 7 3 júl 13:01 word.txt 
command: bash cycle 
á.txt is a file 
command: find . -name á.txt -print 
command: find . -type f -print | grep á.txt 
command: find . -type f -print | fgrep -f word.txt 

Also, nur die bash die Datei gefunden á.txt nein, find noch grep. :(

zuerst auf apple.stackexchange Frage gestellt und one answer suggesting die iconv zum Umwandeln von Dateinamen zu verwenden.

$ find . -name $(iconv -f utf-8 -t utf-8-mac <<< á.txt) 

Während diese Arbeiten für die „OS X“ ist, aber es ist trotzdem schrecklich. (Um eine andere eingeben .. Befehl für jedes uTF8-String an das Terminal, was eintritt)

ich versuche, eine allgemeine Cross-Plattform-bash Programmierung Lösung zu finden, so sind die Fragen:

  • Warum auf dem OS X die bash "found" die Datei und die find nicht?

und

  • Wie Cross-Plattform-Bash-Skript wo Unicode-Dateinamen in einer Datei gespeichert sind zu schreiben.
  • die nur Lösung ist spezielle Versionen schreiben nur für OS X mit dem iconv?
  • existiert portable Lösung für andere Skriptsprachen wie perl und so?

Ps: und schließlich nicht wirklich Frage der Programmierung, sondern fragen, was rationale Entscheidung mit zerlegten Dateinamen hinter Apple ist, was nicht schön mit Kommandozeile utf8

EDIT

spielt Einfach od.

$ ls | od -bc 
0000000 141 314 201 056 164 170 164 012 167 157 162 144 056 164 170 164 
      a ́ ** . t x t \n w o r d . t x t 
0000020 012                
      \n 

und

$ od -bc word.txt 
0000000 303 241 056 164 170 164 012          
      á ** . t x t \n          
0000007 

so die

$ while read -r line; do echo "$line" | od -bc; done < word.txt 
0000000 303 241 056 164 170 164 012          
      á ** . t x t \n          
0000007 

und outpout von einem Fund ist die gleiche wie ls

$ find . -print | od -bc 
0000000 056 012 056 057 167 157 162 144 056 164 170 164 012 056 057 141 
      . \n . / w o r d . t x t \n . / a 
0000020 314 201 056 164 170 164 012          
      ́ ** . t x t \n  

So ist der Gehalt an word.txt IST ANDERS was Datei wird aus seinem Inhalt erstellt. Daher haben immer noch keine Erklärung, warum die bash die Datei gefunden.

Antwort

3

Unicode ist schwer. Wiederholen Sie es jedes Mal, wenn Sie Ihre Zähne putzen.

Ihr á.txt Dateiname enthält 5 Zeichen, von denen á der lästige ist. Es gibt mehrere Möglichkeiten, á als eine Folge von Unicode-Codepunkten darzustellen. Es gibt die vorkompo- nierte Darstellung und die zerlegte. Leider ist die meiste Software nicht darauf vorbereitet, mit Charakteren umzugehen, sondern sich stattdessen auf Codepunkte zu konzentrieren (ja, die meisten Programme sind cr * p). Dies bedeutet, dass die Software bei vorkompo- nierten und zerlegten Darstellungen desselben Zeichens diese nicht als identisch erkennt.

Sie haben eine vorkomposierte á, dargestellt als Unicode-Codestelle U + 00E1 LATIN KLEINER BUCHSTABE A MIT AKUTE. Windows verwendet die vorkompilierte Darstellung. Mac-Dateisysteme bestehen auf der zerlegten Darstellung (naja, meistens; utf-8-mac zerlegt bestimmte Zeichenbereiche nicht, aber á wird in Ordnung zerlegt). Also auf einem Mac Ihre á wird U + 0061 LATEIN KLEINEN BRIEF A gefolgt von U + 0301 KOMBINIEREN AKUTE ACCENT (Schreiben von der Spitze meines Kopfes, kein Mac handy). Linux-Dateisysteme akzeptieren, was auch immer Sie anwerfen.

Wenn Sie geben find eine vorverfasstes á, es wird nicht eine Datei mit einer zerlegt á in seinem Namen, weil es nicht bereit ist, mit diesem brouhaha zu beschäftigen.

Also, was ist die Lösung? Es gibt keine.Wenn Sie mit Unicode umgehen wollen, müssen Sie Defekte der gängigen Tools umgehen.

Hier ist eine etwas weniger hässliche Problemumgehung. Schreiben Sie eine kleine bash-Funktion (mit iconv oder was auch immer), die für jedes System eine Repräsentation konvertiert, die auf diesem System akzeptabel ist, und sie überall verwenden. Nennen wir es u8:

find . -name $(u8 $myfilename) -print 
find . -name -type f -print | fgrep $(u8 $myfilename) 

und so weiter. Ziemlich ist es nicht, aber es sollte funktionieren.

Oh, und ich denke, wir sollten alle beginnen, Fehlerberichte für diese cr * p zu senden. Unsere Software sollte schließlich versuchen, grundlegende menschliche Konzepte wie Charaktere zu verstehen (ich fange nicht einmal an, über Strings zu sprechen). Codepunkte schneiden es einfach nicht aus, auch wenn sie Unicode-Codepunkte sind.

+0

Also, die 'bash' (kompiliert für OS X) das vorkompilierte 'á' bei der Suche nach Dateinamen in zerlegte' á' und andere Dienstprogramme wie find, grep etc .. richtig intern transformiert. So wie man "portable" Skripte schreibt, benutzt man wenn möglich nur "pure bash" ... oder? – jm666

+0

* Also, die bash (für OS X kompiliert) richtig intern die vorkomposierte а * Well warum nicht? Ich habe die Quelle nicht angeschaut, aber es ist das Richtige. –

+0

ok, akzeptiere die Antwort - hauptsächlich für: "Unicode ist hart" und "die Software ist Mist" :) :) - mit meinem Zusatz: Die meisten os ist die Software ein Niveau aus dem 19. Jahrhundert und weiß nichts über Benutzerbedürfnisse. Vor allem Software-Firmen, Apple auch :(. Linux ist (meistens) ok. Shigh. Danke :) – jm666

2

Erstellen der Datei mit touch und Testen ihrer Existenz mit [[ -e "$line" ]] verwendet die gleiche Codierung, so dass die Datei gefunden wird.

Das Testen seiner Existenz mit find -name und find -print scheint verschiedene Codierungen zu verwenden. Ich schlage vor, den Ausgang von find -print in einen Hexdumper zu leiten (xxd oder od -x oder ähnlich). Dies wird Ihnen wahrscheinlich zeigen, welche Kodierung find verwendet, wenn Sie -print verwenden (und dies wird wahrscheinlich auch verwendet werden, wenn Sie -name verwenden).

Die allgemeine Lösung für das Kodieren von Problemen ist immer: VERWENDEN SIE NUR EINE KODIERUNG. In Ihrem Fall sollten Sie entscheiden, welcher Punkt einfacher zu übernehmen ist. Sie können die Kodierung bei der Erstellung der Datei ändern (touch "$(iconv -f utf-8 -t utf-8-mac <<< á.txt)") oder ähnlich) oder ändern Sie, was Sie geben find (die Lösung in Ihrer Frage bereits gegeben). Da bash selbst scheinbar mit den Unicode-Dateinamen zurechtkommt und nur find dieses Problem zu haben scheint, würde ich auch vorschlagen, dort die notwendigen Konvertierungen vorzunehmen. Vielleicht gibt es sogar eine Konfigurationsoption für die Mac OS-Find-Version, die angibt, welche Kodierung für die Befehle -name und -print verwendet werden soll.

+0

Leider nicht. Siehe die Änderung. Habe noch keine Erklärung warum die 'bash' die Datei gefunden hat. Und immer noch keine Lösung Wie schreibt man ein SCRIPT was auf ANY (major) platform läuft, also linux, freebsd, OS X, (und vielleicht windows/cygwin) auch ... – jm666