Comment faire pour que iconv remplace le fichier d'entrée par la sortie convertie?

70

J'ai un script bash qui énumère tous les fichiers * .php d'un répertoire et s'applique iconvà celui-ci. Ceci est affiché dans STDOUT.

Étant donné que l'ajout du -oparamètre (selon mon expérience) écrit en fait un fichier vide probablement avant que la conversion ait lieu, comment puis-je ajuster mon script pour qu'il effectue la conversion, puis écrase le fichier d'entrée?

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file"
done
meder omuraliev
la source

Réponses:

76

Cela ne fonctionne pas, car il iconvcrée d’abord le fichier de sortie (puisque le fichier existe déjà, il le tronque), puis commence à lire son fichier d’entrée (qui est maintenant vide). La plupart des programmes se comportent de cette façon.

Créez un nouveau fichier temporaire pour la sortie, puis déplacez-le.

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

Si votre plate-forme iconvn'en possède pas -o, vous pouvez utiliser une redirection de shell dans le même sens.

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

L' spongeutilitaire de Colin Watson (inclus dans les moreutils de Joey Hess ) automatise ceci:

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

Cette réponse ne s’applique pas seulement à iconvmais à n’importe quel programme de filtrage. Quelques cas particuliers méritent d’être mentionnés:

  • Sed et Perl -pont une -ioption pour remplacer les fichiers en place.
  • Si votre dossier est extrêmement grand, votre filtre ne modifier ou supprimer certaines parties , mais jamais d' ajouter des choses (par exemple grep, tr, sed 's/long input text/shorter text/'), et vous aimez vivre dangereusement, vous pouvez vraiment modifier le fichier en place (les autres solutions mentionnées créent ici une nouveau fichier de sortie et déplacez-le à la fin pour que les données d'origine restent inchangées si la commande est interrompue pour une raison quelconque).
Gilles, arrête de faire le mal
la source
3
Je ne suis pas tout à fait sûr de savoir si la paternité de spongedoit être attribuée exclusivement à Joey Hess; c’est le paquet moreutilsqui comprend spongece qu’il maintient, mais en ce qui concerne l’origine de sponge, en suivant les liens de la page d’accueil de moreutils, j’ai trouvé ce message posté et suggéré par Colin Watson: "Joey écrit à propos du manque de nouveaux outils rentrez dans la philosophie Unix. Ce que j’ai écrit de ce type est ce que je préfère sponge"(lun. 06 févr. 2006).
imz - Ivan Zakharyaschev
3
J'utilise Mac OS, il n'y a pas d'option -o dans iconv, je dois changer `iconv -f cp1251 -t utf8 -o" $ file.new "" $ file "` àiconv -f cp1251 -t utf8 "$file" > "$file.new"
code4j
Certaines commandes, par exemple sort, sont assez intelligentes en ce qui concerne les -oparamètres. Si elles détectent un fichier de sortie identique à une entrée, elles gèrent en interne un fichier temporaire afin que celui-ci fonctionne.
jesjimher
56

Une alternative est d' recodeutiliser la bibliothèque libiconv pour certaines conversions. Son comportement est de remplacer le fichier d'entrée par la sortie, cela fonctionnera donc:

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

Comme recodeaccepte plusieurs fichiers d’entrée en paramètre, vous pouvez épargner la forboucle:

recode cp1251..utf8 *.php
homme au travail
la source
2
Merci, cela mérite plus de votes positifs. Je me demandais simplement où était fixé le manuel sur les 2 points entre les encodages ...
neurino
2
«REQUEST ressemble souvent à BEFORE..AFTER, BEFORE et AFTER étant des jeux de caractères.» Ce manuel est en effet difficile à suivre avec tous ces points doubles (qui font partie de la syntaxe) et les points triples (qui en signifient davantage). Un conseil: essayez info recodeplutôt. Est plus verbeux.
manatwork
4

Pour l'instant

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

fonctionne comme un charme

Galeksandrp
la source
5
Au début, j'ai effectivement pensé que cela fonctionnait. Mais il semble que la sortie dépassant 32K soit coupée, et avec encore plus d’entrée, elle déclenche des vidages mémoire.
x-yuri
1

Vous pouvez utiliser Vim en mode Ex:

ex -sc '%!iconv -f cp1251 -t utf8' -cx "$file"
  1. % sélectionner toutes les lignes

  2. ! commande d'exécution

  3. x sauver et fermer

Steven Penny
la source
0

Voici un exemple simple . Cela devrait vous donner assez d’informations pour commencer.

#!/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
la source
0
echo "`iconv -f cp1251 -t utf8 $file`" > "$file"

travaille pour moi

CoNsTaR
la source
0

Vous pouvez utiliser find, au moins cela a fonctionné pour moi sur Raspbian Stretch:

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

Une option consiste à utiliser perll'interface iconvet le -imode d'édition in-situ de:

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

Avec GNU awk, vous pouvez également faire quelque chose comme:

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

Le ksh93shell a également un >;opérateur pour celui qui stocke la sortie dans un fichier temporaire renommé en fichier redirigé si la commande aboutit:

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