Come posso fare in modo che iconv sostituisca il file di input con l'output convertito?


70

Ho uno script bash che elenca tutti i file * .php in una directory e si applica iconvad esso. Questo ottiene output in STDOUT.

Poiché l'aggiunta del -oparametro (nella mia esperienza) in realtà scrive un file vuoto probabilmente prima che abbia luogo la conversione, come posso modificare il mio script in modo che esegua la conversione, quindi sovrascrivere il file di input?

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

Risposte:


76

Questo non funziona perché iconvprima crea il file di output (poiché il file esiste già, lo tronca), quindi inizia a leggere il suo file di input (che ora è vuoto). La maggior parte dei programmi si comporta in questo modo.

Crea un nuovo file temporaneo per l'output, quindi spostalo in posizione.

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

Se la tua piattaforma iconvnon ha -o, puoi usare un reindirizzamento della shell con lo stesso effetto.

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

L' spongeutilità di Colin Watson (inclusa negli articoli di Joey Hess ) automatizza questo:

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

Questa risposta si applica non solo a iconvma a qualsiasi programma di filtro. Vale la pena ricordare alcuni casi speciali:

  • GNU sed e Perl -phanno -iun'opzione per sostituire i file in atto.
  • Se il file è molto grande, il filtro è solo modificare o rimuovere alcune parti, ma mai l'aggiunta di cose (per esempio grep, tr, sed 's/long input text/shorter text/'), e vi piace vivere pericolosamente, si consiglia di veramente modificare il file in atto (le altre soluzioni di cui qui creano un nuovo file di output e spostarlo in posizione alla fine, in modo che i dati originali rimangano invariati se il comando viene interrotto per qualsiasi motivo).

3
Non sono del tutto sicuro che la paternità di spongedovrebbe essere attribuita esclusivamente a Joey Hess; è il pacchetto moreutilsche include spongeche mantiene, ma per quanto riguarda l'origine sponge, seguendo i collegamenti dalla homepage di moreutils, l'ho trovato originariamente pubblicato e suggerito per l'inclusione di Colin Watson: "Joey scrive della mancanza di nuovi strumenti che si adatta alla filosofia Unix. Il mio preferito di queste cose che ho scritto è sponge"(Lun, 06 Feb 2006).
imz - Ivan Zakharyaschev

3
Uso Mac OS, non c'è alcuna opzione -o in iconv, devo cambiare `iconv -f cp1251 -t utf8 -o" $ file.new "" $ file "` iniconv -f cp1251 -t utf8 "$file" > "$file.new"
code4j

Alcuni comandi, ad esempio sort, sono piuttosto intelligenti per quanto riguarda i -oparametri e se rilevano il file di output è lo stesso dell'input, gestiscono internamente un file temporaneo in modo che funzioni.
jesjimher,

56

Un'alternativa è recodeche utilizza la libreria libiconv per alcune conversioni. Il suo comportamento è sostituire il file di input con l'output, quindi funzionerà:

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

Poiché recodeaccetta più file di input come parametro, è possibile risparmiare il forciclo:

recode cp1251..utf8 *.php

2
Grazie, questo merita più voti. Mi chiedo solo dove siano fissati nel manuale i 2 punti tra le codifiche ...
neurino,

2
"RICHIESTA spesso sembra PRIMA ... DOPO, con PRIMA e DOPO essere caratteri." Quel manuale è davvero difficile da seguire con tutti quei punti doppi (che fanno parte della sintassi) e punti tripli (che significano più di questo). Un consiglio: prova info recodeinvece. È più prolisso.
arte

4

Per adesso

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

funziona come un fascino


5
All'inizio, ho davvero pensato che funzionasse. Ma sembra che l'uscita superiore a 32K sia tagliata e con ancora più input innesca dump core.
x-yuri,

1

Puoi usare Vim in modalità Ex:

ex -sc '%!iconv -f cp1251 -t utf8' -cx "$file"
  1. % seleziona tutte le righe

  2. ! esegui comando

  3. x salva e chiudi


0

Ecco un semplice esempio . Dovrebbe darti informazioni sufficienti per iniziare.

#!/bin/bash
#conversor.sh
#Author.....: dede.exe
#E-mail.....: dede.exe@gmail.com
#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;

0
echo "`iconv -f cp1251 -t utf8 $file`" > "$file"

per me va bene


0

Puoi usare find, almeno questo ha funzionato per me su Raspbian Stretch:

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

0

Un'opzione è utilizzare perll'interfaccia iconve la sua -imodalità per la modifica sul posto:

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

Con GNU awk, puoi anche fare qualcosa del tipo:

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

La ksh93shell ha anche un >;operatore per ciò che memorizza l'output in un file temporaneo che viene rinominato nel file reindirizzato se il comando ha avuto esito positivo:

for f in *.php; do
  iconv -f cp1252 -t utf-8 < $f >; $f
done
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.