¿Cómo puedo hacer que iconv reemplace el archivo de entrada con la salida convertida?


70

Tengo un script bash que enumera a través de cada archivo * .php en un directorio y se aplica iconva él. Esto obtiene salida en STDOUT.

Dado que agregar el -oparámetro (en mi experiencia) en realidad escribe un archivo en blanco probablemente antes de que tenga lugar la conversión, ¿cómo puedo ajustar mi script para que realice la conversión y luego sobrescribe el archivo de entrada?

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

Consulte también Advertencia sobre ">" .
— G-Man el

Respuestas:


76

Esto no funciona porque iconvprimero crea el archivo de salida (dado que el archivo ya existe, lo trunca), luego comienza a leer su archivo de entrada (que ahora está vacío). La mayoría de los programas se comportan de esta manera.

Cree un nuevo archivo temporal para la salida, luego muévalo a su lugar.

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

Si su plataforma iconvno tiene -o, puede usar una redirección de shell para el mismo efecto.

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

La spongeutilidad de Colin Watson (incluida en moreutils de Joey Hess ) automatiza esto:

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

Esta respuesta se aplica no solo iconva cualquier programa de filtro, sino también a él. Vale la pena mencionar algunos casos especiales:

  • GNU sed y Perl -ptienen una -iopción para reemplazar archivos en su lugar.
  • Si el archivo es muy grande, el filtro sólo está modificando o eliminando algunas partes, pero nunca añadir cosas (por ejemplo grep, tr, sed 's/long input text/shorter text/'), y te gusta vivir peligrosamente, es posible que desee realmente modificar el archivo en su lugar (las otras soluciones mencionadas aquí crean una nuevo archivo de salida y muévalo a su lugar al final, de modo que los datos originales no cambien si el comando se interrumpe por cualquier motivo).

3
No estoy muy seguro de si la autoría de spongedebe atribuirse exclusivamente a Joey Hess; es el paquete moreutilsque incluye lo spongeque mantiene, pero en lo que respecta al origen de sponge, siguiendo los enlaces de la página de inicio de moreutils, he encontrado originalmente publicado y sugerido para su inclusión por Colin Watson: "Joey escribe sobre la falta de nuevas herramientas que encaja en la filosofía de Unix. Mi favorito de las cosas que he escrito es sponge"(Lun, 06 de febrero de 2006).
— imz - Ivan Zakharyaschev

3
Uso Mac OS, no hay opción -o en iconv, tengo que cambiar `iconv -f cp1251 -t utf8 -o" $ file.new "" $ file "` aiconv -f cp1251 -t utf8 "$file" > "$file.new"
— code4j

Algunos comandos, como sort, son bastante inteligentes con respecto a los -oparámetros, y si detectan que el archivo de salida es igual a la entrada, administran internamente un archivo temporal, por lo que simplemente funciona.
— jesjimher

56

Una alternativa es recode, que utiliza la biblioteca libiconv para algunas conversiones. Su comportamiento es reemplazar el archivo de entrada con la salida, por lo que esto funcionará:

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

Como recodeacepta múltiples archivos de entrada como parámetro, puede ahorrar el forbucle:

recode cp1251..utf8 *.php

2
Gracias, esto merece más votos a favor. Solo me pregunto dónde se mira en el manual sobre los 2 puntos entre las codificaciones ...
— neurino

2
"SOLICITUD a menudo se ve ANTES ... DESPUÉS, ANTES y DESPUÉS de ser charsets". Ese manual es realmente difícil de seguir con todos esos puntos dobles (que son parte de la sintaxis) y puntos triples (lo que significa más de esto). Un consejo: intente en su info recodelugar. Es más detallado.
— manatwork

4

Por ahora

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

Funciona de maravilla


55
Al principio, realmente pensé que funcionaba. Pero parece que la salida que excede los 32K se corta, y con aún más entrada desencadena volcados de núcleo.
— x-yuri

1

Puede usar Vim en modo Ex:

ex -sc '%!iconv -f cp1251 -t utf8' -cx "$file"
  1. % seleccione todas las líneas

  2. ! ejecutar comando

  3. x guardar y cerrar


0

Aquí hay un ejemplo simple . Debería darle una información suficiente para comenzar.

#!/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"

funciona para mi


0

Puedes usar find, al menos esto funcionó para mí en Raspbian Stretch:

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

0

Una opción es usar perlla interfaz iconvy su -imodo para la edición in situ:

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

Con GNU awk, también puedes hacer algo como:

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

El ksh93shell también tiene un >;operador para aquello que almacena la salida en un archivo temporal que se renombra al archivo redirigido si el comando fue exitoso:

for f in *.php; do
  iconv -f cp1252 -t utf-8 < $f >; $f
done
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.