ฉันจะทำให้ iconv แทนที่ไฟล์อินพุตด้วยเอาต์พุตที่ถูกแปลงได้อย่างไร?


69

ฉันมีสคริปต์ทุบตีซึ่งระบุผ่านทุกไฟล์ * .php ในไดเรกทอรีและนำiconvไปใช้กับมัน สิ่งนี้ได้รับผลลัพธ์ใน STDOUT

เนื่องจากการเพิ่ม-oพารามิเตอร์ (จากประสบการณ์ของฉัน) จริง ๆ แล้วเขียนไฟล์เปล่าก่อนที่จะเกิดการแปลงฉันจะปรับสคริปต์ของฉันเพื่อให้เกิดการแปลงจากนั้นจึงเขียนทับไฟล์อินพุต

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

ดูเพิ่มเติมคำเตือนเกี่ยวกับการ“>”
G-Man

คำตอบ:


76

สิ่งนี้ไม่ทำงานเนื่องจากiconvสร้างไฟล์เอาต์พุตเป็นครั้งแรก (เนื่องจากไฟล์มีอยู่แล้วจะตัดทอน) จากนั้นเริ่มอ่านไฟล์อินพุต (ซึ่งตอนนี้ว่างเปล่า) โปรแกรมส่วนใหญ่ทำตัวแบบนี้

สร้างไฟล์ชั่วคราวใหม่สำหรับเอาต์พุตจากนั้นย้ายไปไว้ที่เดิม

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

หากแพลตฟอร์มของคุณiconvไม่มี-oคุณสามารถใช้การเปลี่ยนเส้นทางเชลล์เพื่อให้มีผลเหมือนกัน

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

spongeโปรแกรมอรรถประโยชน์ของ Colin Watson (รวมอยู่ในโปรแกรมเพิ่มเติมของJoey Hess ) ทำให้สิ่งนี้เป็นไปโดยอัตโนมัติ:

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

คำตอบนี้ใช้ไม่เพียงiconvแต่กับโปรแกรมตัวกรองใด ๆ กรณีพิเศษสองสามอย่างที่ควรกล่าวถึง:

  • GNU sed และ Perl -pมี-iตัวเลือกสำหรับแทนที่ไฟล์
  • หากไฟล์ของคุณมีขนาดใหญ่มากตัวกรองของคุณเป็นเพียงการปรับเปลี่ยนหรือลบบางส่วน แต่ไม่เคยเพิ่มสิ่ง (เช่นgrep, tr, sed 's/long input text/shorter text/') และคุณชอบใช้ชีวิตอันตรายคุณอาจต้องการที่แท้จริงแก้ไขไฟล์ในสถานที่ (แก้ปัญหาอื่น ๆ ที่กล่าวถึงที่นี่สร้าง ไฟล์เอาต์พุตใหม่และย้ายไปไว้ที่ท้ายดังนั้นข้อมูลต้นฉบับจะไม่เปลี่ยนแปลงหากคำสั่งถูกขัดจังหวะด้วยเหตุผลใดก็ตาม)

3
ฉันค่อนข้างไม่แน่ใจว่าการประพันธ์ของspongeควรมีการอ้างถึงโดยเฉพาะกับ Joey Hess หรือไม่ เป็นแพ็กเกจmoreutilsที่รวมถึงspongeที่เขาดูแล แต่ตามที่มาของการspongeติดตามลิงก์จากหน้าแรกของmoreutilsฉันได้พบว่าโพสต์ดั้งเดิมและแนะนำสำหรับการรวมโดย Colin Watson: "โจอี้เขียนเกี่ยวกับการขาดเครื่องมือใหม่ที่ สอดคล้องกับปรัชญาของ Unix สิ่งที่ฉันชอบในสิ่งที่ฉันเขียนคือsponge"(จันทร์, 06 ก.พ. 2549)
imz - Ivan Zakharyaschev

3
ฉันใช้ Mac OS ไม่มีตัวเลือก -o ใน iconv ฉันต้องเปลี่ยน `iconv -f cp1251 -t utf8 -o" $ file.new "" $ file "" เป็นiconv -f cp1251 -t utf8 "$file" > "$file.new"
code4j

คำสั่งบางคำสั่งsortนั้นค่อนข้างฉลาดและเกี่ยวข้องกับ-oพารามิเตอร์และหากตรวจพบไฟล์เอาต์พุตเหมือนกับอินพุตพวกเขาจัดการไฟล์ชั่วคราวภายในดังนั้นมันจึงใช้งานได้
jesjimher

56

อีกทางเลือกหนึ่งคือrecodeซึ่งใช้ไลบรารี libiconv สำหรับการแปลงบางอย่าง พฤติกรรมของมันคือการแทนที่ไฟล์อินพุตด้วยเอาต์พุตดังนั้นสิ่งนี้จะได้ผล:

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

ในฐานะที่recodeยอมรับหลายไฟล์อินพุตเป็นพารามิเตอร์คุณสามารถสำรองforลูป:

recode cp1251..utf8 *.php

2
ขอบคุณสิ่งนี้สมควรได้รับการโหวตมากขึ้น เพียงแค่สงสัยว่าที่ไหนจ้องในคู่มือเกี่ยวกับ 2 จุดระหว่างการเข้ารหัส ...
neurino

2
“ คำขอมักจะดูเหมือนก่อน .. ด้วยก่อนและหลังเป็นชุดอักขระ” คู่มือเล่มนั้นยากที่จะตามด้วยจุดคู่เหล่านั้น (ซึ่งเป็นส่วนหนึ่งของไวยากรณ์) และจุดสามจุด (ซึ่งหมายถึงสิ่งนี้มากกว่า) คำแนะนำ: ลองinfo recodeแทน เป็น verbose มากขึ้น
จัดการ

4

สำหรับตอนนี้

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

ทำงานเหมือนจับใจ


5
ตอนแรกฉันคิดว่ามันใช้งานได้จริง แต่ดูเหมือนว่าเอาต์พุตเกิน 32K จะถูกตัดออกและยิ่งมีอินพุตมากขึ้น
x-yuri


0

นี่คือตัวอย่างง่ายๆ ควรให้ข้อมูลเพียงพอในการเริ่มต้น

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

คุณสามารถใช้ find อย่างน้อยก็ใช้งานได้กับ Raspbian Stretch:

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

0

ทางเลือกหนึ่งคือใช้perlอินเทอร์เฟซของiconvและ-iโหมดสำหรับการแก้ไขในที่:

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

ด้วย GNU awkคุณสามารถทำสิ่งต่าง ๆ เช่น:

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

ksh93เปลือกนอกจากนี้ยังมี>;ผู้ประกอบการที่ส่งออกที่เก็บในไฟล์ temp ซึ่งถูกเปลี่ยนชื่อไฟล์เปลี่ยนเส้นทางถ้าคำสั่งที่ประสบความสำเร็จไปนี้:

for f in *.php; do
  iconv -f cp1252 -t utf-8 < $f >; $f
done
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.