Bagaimana saya bisa membuat iconv mengganti file input dengan output yang dikonversi?

70

Saya memiliki skrip bash yang menyebutkan setiap file * .php di direktori dan berlaku iconvuntuk itu. Ini mendapatkan output dalam STDOUT.

Karena menambahkan -oparameter (menurut pengalaman saya) sebenarnya menulis file kosong mungkin sebelum konversi terjadi, bagaimana saya bisa menyesuaikan skrip saya sehingga melakukan konversi, lalu menimpa file input?

for file in *.php
do
    iconv -f cp1251 -t utf8 "$file"
done
omeraliev meder
sumber
Lihat juga Peringatan tentang ">" .
G-Man

Jawaban:

76

Ini tidak berfungsi karena iconvpertama-tama membuat file output (karena file sudah ada, memotongnya), kemudian mulai membaca file inputnya (yang sekarang kosong). Sebagian besar program berperilaku seperti ini.

Buat file sementara yang baru untuk output, lalu pindahkan ke tempatnya.

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

Jika platform iconvAnda tidak memiliki -o, Anda dapat menggunakan pengalihan shell untuk efek yang sama.

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

spongeUtilitas Colin Watson (termasuk dalam moreutils Joey Hess ) mengotomatisasi ini:

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

Jawaban ini berlaku tidak hanya untuk iconvtetapi untuk program filter apa pun. Beberapa kasus khusus perlu disebutkan:

  • GNU sed dan Perl -pmemiliki -iopsi untuk mengganti file di tempat.
  • Jika file Anda sangat besar, filter Anda hanya memodifikasi atau menghapus beberapa bagian tetapi tidak pernah menambahkan hal-hal (misalnya grep, tr, sed 's/long input text/shorter text/'), dan Anda seperti tinggal berbahaya, Anda mungkin ingin benar-benar memodifikasi file di tempat (solusi lain yang disebutkan di sini membuat file output baru dan pindahkan ke tempatnya di akhir, sehingga data asli tidak berubah jika perintah terputus karena alasan apa pun).
Gilles 'SANGAT berhenti menjadi jahat'
sumber
3
Saya tidak yakin apakah kepengarangan spongeharus dikaitkan secara eksklusif dengan Joey Hess; itu adalah paket moreutilsyang termasuk spongeyang dia pertahankan, tetapi mengenai asal usulnya sponge, dengan mengikuti tautan dari beranda moreutils, saya telah menemukannya pada awalnya diposting dan disarankan untuk dimasukkan oleh Colin Watson: "Joey menulis tentang kurangnya alat baru yang cocok dengan filosofi Unix. Favorit saya dari hal-hal seperti yang saya tulis adalah sponge"(Senin, 06 Februari 2006)
imz - Ivan Zakharyaschev
3
Saya menggunakan Mac OS, tidak ada opsi -o di iconv, saya harus mengubah `iconv -f cp1251 -t utf8 -o" $ file.new "" $ file "` keiconv -f cp1251 -t utf8 "$file" > "$file.new"
code4j
Beberapa perintah, seperti sort, cukup pintar tentang -oparameter, dan jika mereka mendeteksi file output sama dengan input mereka secara internal mengelola file temp sehingga hanya berfungsi.
jesjimher
56

Alternatifnya adalah recode, yang menggunakan perpustakaan libiconv untuk beberapa konversi. Perilakunya adalah mengganti file input dengan output, jadi ini akan berfungsi:

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

Saat recodemenerima beberapa file input sebagai parameter, Anda dapat menggunakan forloop:

recode cp1251..utf8 *.php
manatwork
sumber
2
Terima kasih, ini layak mendapat lebih banyak upvotes. Hanya ingin tahu di mana ditatap secara manual tentang 2 titik di antara pengkodean ...
neurino
2
“PERMINTAAN sering terlihat SEBELUM..MULAI, dengan SEBELUM dan SETELAH menjadi charset.” Manual itu memang sulit diikuti dengan semua titik ganda (yang merupakan bagian dari sintaks) dan tiga titik (yang berarti lebih dari ini). Saran: coba info recodesaja. Lebih banyak bertele-tele.
manatwork
4

Untuk sekarang

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

bekerja seperti pesona

galeksandrp
sumber
5
Awalnya, saya pikir itu berhasil. Tetapi tampaknya output yang melebihi 32K terputus, dan dengan lebih banyak input akan memicu dump inti.
x-yuri
1

Anda dapat menggunakan Vim dalam mode Ex:

ex -sc '%!iconv -f cp1251 -t utf8' -cx "$file"
  1. % pilih semua garis

  2. ! jalankan perintah

  3. x Simpan dan tutup

Steven Penny
sumber
0

Ini adalah contoh sederhana . Seharusnya memberi Anda cukup info untuk memulai.

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

bekerja untukku

KoNsTaR
sumber
0

Anda dapat menggunakan find, setidaknya ini bekerja untuk saya di Raspbian Stretch:

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

Salah satu opsi adalah menggunakan perl antarmuka untuk iconvdan -imodenya untuk mengedit inplace:

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

Dengan GNU awk, Anda juga dapat melakukan sesuatu seperti:

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

The ksh93shell juga memiliki >;operator yang untuk itu yang menyimpan output dalam file temp yang berganti nama menjadi file diarahkan jika perintah berhasil:

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