Como posso fazer o iconv substituir o arquivo de entrada pela saída convertida?

61

Eu tenho um script bash que enumera todos os arquivos * .php em um diretório e aplica iconv a ele. Isso obtém a saída no STDOUT.

Como a adição do parâmetro -o (na minha experiência) realmente grava um arquivo em branco provavelmente antes que a conversão ocorra, como posso ajustar meu script para que ele faça a conversão e, em seguida, sobrescreva o arquivo de entrada?

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file"
done
    
por meder omuraliev 28.03.2011 / 21:09

8 respostas

73

Isso não está funcionando porque iconv primeiro cria o arquivo de saída (já que o arquivo já existe, ele o trunca), então começa a ler seu arquivo de entrada (que agora está vazio). A maioria dos programas se comporta dessa maneira.

Crie um novo arquivo temporário para a saída e, em seguida, mova-o para o lugar.

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

Se a iconv da sua plataforma não tiver -o , você poderá usar um redirecionamento de shell para o mesmo efeito.

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

Colin Watson's sponge utility (incluído em moreutils de Joey Hess ) automatiza isso:

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

Esta resposta não se aplica apenas a iconv , mas a qualquer programa de filtro. Alguns casos especiais merecem destaque:

  • O GNU sed e o Perl -p têm uma opção -i para substituir os arquivos no lugar.
  • Se o seu arquivo é extremamente grande, seu filtro está apenas modificando ou removendo algumas partes, mas nunca adicionando coisas (por exemplo, grep , tr , sed 's/long input text/shorter text/' ), e você gosta de viver perigosamente, você pode querer genuinamente < um href="https://unix.stackexchange.com/questions/11067/is-there-a-way-to-modify-a-file-inplace"> modificar o arquivo no lugar (o outras soluções mencionadas aqui criam um novo arquivo de saída e o colocam no lugar no final, portanto, os dados originais permanecem inalterados se o comando for interrompido por qualquer motivo).
por 28.03.2011 / 21:17
49

Uma alternativa é recode , que usa a biblioteca libiconv para algumas conversões. Seu comportamento é substituir o arquivo de entrada pela saída, então isso funcionará:

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

Como recode aceita vários arquivos de entrada como parâmetro, você pode poupar o for loop:

recode cp1251..utf8 *.php
    
por 02.09.2011 / 14:25
4

Por enquanto

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

funciona como um charme

    
por 29.11.2014 / 21:14
1

Você pode usar o Vim no modo Ex:

ex -sc '%!iconv -f cp1251 -t utf8' -cx "$file"
  1. % seleciona todas as linhas

  2. ! comando de execução

  3. x salvar e fechar

por 11.04.2016 / 05:25
0

Aqui está um exemplo simples . Deve dar-lhe uma informação suficiente para começar.

#!/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;
    
por 14.05.2015 / 05:12
0
echo "'iconv -f cp1251 -t utf8 $file'" > "$file"

funciona para mim

    
por 20.04.2017 / 09:01
0

Você pode usar o find, pelo menos isso funcionou para mim no Stretch Raspbian:

find . -type f -name '*php' -execdir iconv -f cp1251 -t UTF-8 '{}' -o '{}'.tmp \; -execdir mv '{}'.tmp '{}' \;
    
por 06.02.2018 / 17:33
0

Uma opção é usar a interface perl para iconv e seu modo -i para edição no local:

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

Com o GNU awk , você também pode fazer algo como:

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

O shell ksh93 também possui um operador >; para aquele que armazena a saída em um arquivo temporário que é renomeado para o arquivo redirecionado se o comando for bem-sucedido:

for f in *.php; do
  iconv -f cp1252 -t utf-8 < $f >; $f
done
    
por 13.06.2018 / 17:24