Wie kann ich festlegen, dass iconv die Eingabedatei durch die konvertierte Ausgabe ersetzt?

70

Ich habe ein Bash-Skript, das alle * .php-Dateien in einem Verzeichnis auflistet und iconvauf sie anwendet . Dies wird in STDOUT ausgegeben.

Da das Hinzufügen des -oParameters (meiner Erfahrung nach) wahrscheinlich vor der Konvertierung tatsächlich eine leere Datei schreibt, wie kann ich mein Skript so anpassen, dass es die Konvertierung durchführt, und dann die Eingabedatei überschreiben?

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file"
done
meder omuraliev
quelle
Siehe auch Warnung zu “>” .
G-Man

Antworten:

76

Dies funktioniert nicht, da iconvzuerst die Ausgabedatei erstellt (da die Datei bereits vorhanden ist, wird sie abgeschnitten) und dann mit dem Lesen der Eingabedatei begonnen wird (die jetzt leer ist). Die meisten Programme verhalten sich so.

Erstellen Sie eine neue temporäre Datei für die Ausgabe, und verschieben Sie sie an ihren Platz.

for file in *.php
do
    iconv -f cp1251 -t utf8 -o "$file.new" "$file" &&
    mv -f "$file.new" "$file"
done

Wenn Ihre Plattform iconvkeine hat -o, können Sie eine Shell-Umleitung verwenden, um den gleichen Effekt zu erzielen.

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file" >"$file.new" &&
    mv -f "$file.new" "$file"
done

Colin Watsons spongeUtility (in Joey Hess 'moreutils enthalten ) automatisiert dies:

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file" | sponge "$file"
done

Diese Antwort gilt nicht nur für iconvFilterprogramme , sondern für alle Filterprogramme. Einige Sonderfälle sind erwähnenswert:

  • GNU sed und Perl -phaben die -iOption, vorhandene Dateien zu ersetzen.
  • Wenn Ihre Datei extrem groß ist, wird Ihr Filter nur ändern oder einige Teile entfernt werden, aber nie Dinge Zugabe (zB grep, tr, sed 's/long input text/shorter text/'), und man mag gefährlich leben, können Sie wirklich wollen, um die Datei an Ort und Stelle ändern (die anderen Lösungen erwähnten hier erstellen neue Ausgabedatei und verschieben Sie sie an ihren Platz am Ende, damit die ursprünglichen Daten unverändert bleiben, wenn der Befehl aus irgendeinem Grund unterbrochen wird.
Gilles
quelle
3
Ich bin nicht ganz sicher, ob die Urheberschaft von spongeausschließlich Joey Hess zugeschrieben werden sollte; es ist das Paket moreutils, spongedas er pflegt, aber in Bezug auf die Herkunft sponge, indem er den Links von der Homepage von folgt moreutils, habe ich festgestellt, dass es ursprünglich von Colin Watson gepostet und zur Aufnahme vorgeschlagen wurde : "Joey schreibt über das Fehlen neuer Werkzeuge, die passen in die Unix-Philosophie. Mein Favorit von solchen Dingen, die ich geschrieben habe, ist sponge"(Mo, 06.02.2006).
imz - Ivan Zakharyaschev
3
Ich benutze Mac OS, gibt es keine Option -o in iconv ist, muss ich `iconv -f CP1251 ändern -t utf8 -o "file.new $" "$ file"` zuiconv -f cp1251 -t utf8 "$file" > "$file.new"
code4j
Einige Befehle, wie z. B. sort, sind in Bezug auf -oParameter ziemlich schlau. Wenn sie feststellen, dass die Ausgabedatei mit der Eingabe identisch ist, verwalten sie intern eine temporäre Datei, damit sie einfach funktioniert.
Jesjimher
56

Eine Alternative ist recode, die für einige Konvertierungen die Bibliothek libiconv verwendet. Sein Verhalten besteht darin, die Eingabedatei durch die Ausgabe zu ersetzen, sodass dies funktioniert:

for file in *.php
do
    recode cp1251..utf8 "$file"
done

Da recodemehrere Eingabedateien als Parameter akzeptiert werden, können Sie die forSchleife schonen :

recode cp1251..utf8 *.php
Mann bei der Arbeit
quelle
2
Danke, das verdient mehr Gegenstimmen.
Ich
2
"REQUEST sieht oft wie BEFORE..AFTER aus, wobei BEFORE und AFTER Zeichensätze sind." Dieses Handbuch ist in der Tat schwer zu befolgen mit all den Doppelpunkten (die Teil der Syntax sind) und Dreifachpunkten (die mehr davon bedeuten). Ein Tipp: versuchen Sie es info recodestattdessen. Ist ausführlicher.
Handarbeit
4

Zur Zeit

find . -name '*.php' -exec iconv -f CP1251 -t UTF-8 {} -o {} \;

klappt wunderbar

galeksandrp
quelle
5
Zuerst dachte ich tatsächlich, dass es funktioniert. Es scheint jedoch, dass die Ausgabe über 32 KB abgeschnitten ist und bei noch mehr Eingaben Core-Dumps ausgelöst werden.
X-Yuri
1

Sie können Vim im Ex-Modus verwenden:

ex -sc '%!iconv -f cp1251 -t utf8' -cx "$file"
  1. % Wählen Sie alle Zeilen aus

  2. ! Führen Sie den Befehl aus

  3. x speichern und schließen

Steven Penny
quelle
0

Hier ist ein einfaches Beispiel . Es sollte Ihnen genügend Informationen geben, um loszulegen.

#!/bin/bash
#conversor.sh
#Author.....: dede.exe
#E-mail.....: [email protected]
#Description: Convert all files to a another format
#             It's not a safe way to do it...
#             Just a desperate script to save my life...
#             Use it such a last resort...

to_format="utf8"
file_pattern="*.java"

files=`find . -name "${file_pattern}"`

echo "==================== CONVERTING ===================="

#Try convert all files in the structure
for file_name in ${files}
do
        #Get file format
        file_format=`file $file_name --mime-encoding | cut -d":" -f2 | sed -e 's/ //g'`

        if [ $file_format != $to_format ]; then

                file_tmp="${unit_file}.tmp"

                #Rename the file to a temporary file
                mv $file_name $file_tmp

                #Create a new file with a new format.
                iconv -f $file_format -t $to_format $file_tmp > $file_name

                #Remove the temporary file
                rm $file_tmp

                echo "File Name...: $file_name"
                echo "From Format.: $file_format"
                echo "To Format...: $to_format"
                echo "---------------------------------------------------"

        fi
done;
dede.exe
quelle
0
echo "`iconv -f cp1251 -t utf8 $file`" > "$file"

funktioniert bei mir

CoNsTaR
quelle
0

Du kannst find verwenden, zumindest funktionierte dies für mich auf Raspbian Stretch:

find . -type f -name '*php' -execdir iconv -f cp1251 -t UTF-8 '{}' -o '{}'.tmp \; -execdir mv '{}'.tmp '{}' \;
Rannala
quelle
0

Eine Möglichkeit besteht darin, perldie Benutzeroberfläche iconvund den -iModus für die direkte Bearbeitung zu verwenden:

perl -MText::Iconv -i -pe '
  BEGIN{$i=Text::Iconv->new(qw(cp1252 UTF-8));$i->raise_error(1)}
  $_ = $i->convert($_)' ./*.php

Mit GNU awkkönnen Sie auch Folgendes tun:

gawk -v cmd='iconv -f cp1252 -t utf-8' -i inplace '
  {print | cmd}; ENDFILE {close(cmd)}' ./*.php

Die ksh93Shell hat auch einen >;Operator, der die Ausgabe in einer temporären Datei speichert, die bei erfolgreichem Befehl in die umgeleitete Datei umbenannt wird:

for f in *.php; do
  iconv -f cp1252 -t utf-8 < $f >; $f
done
Stéphane Chazelas
quelle