Як можна змусити iconv замінити вхідний файл на перетворений вихід?


69

У мене є скрипт bash, який перераховує кожен * .php файл у каталозі та застосовується iconvдо нього. Це отримує вихід у STDOUT.

Оскільки додавання -oпараметра (на мій досвід) фактично записує порожній файл, ймовірно, до того, як відбудеться перетворення, як я можу налаштувати свій скрипт, щоб він перетворив, а потім перезаписав вхідний файл?

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

Відповіді:


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Утиліта Коліна Уотсона (включена в додаткові програми 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слід авторство приписувати виключно Джої Гессу; це пакет, moreutilsякий включає spongeте, що він підтримує, але що стосується походження sponge, перейшовши за посиланнями на домашній сторінці moreutils, я знайшов його спочатку розміщеним та запропонованим для включення Коліном Уотсоном: "Джої пише про відсутність нових інструментів, які вписатись у філософію Unix. Найулюбленішим з таких речей, які я написав, є sponge"(пн, 06 лютого 2006 р.).
imz - Іван Захарящев

3
Я використовую Mac OS, в iconv немає опції -o, я повинен змінити `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замість цього. Є більш багатослівним.
манатура

4

Зараз

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

працює як шарм


5
Спочатку я справді думав, що це працює. Але, схоже, вихід, що перевищує 32 К, відключається, і при ще більшому введенні він запускає основні скиди.
x-yuri

1

Ви можете використовувати Vim в режимі Ex:

ex -sc '%!iconv -f cp1251 -t utf8' -cx "$file"
  1. % виберіть усі рядки

  2. ! запустити команду

  3. x зберегти і закрити


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Оболонка також має >;оператор для цього , який зберігає вихідні дані у вигляді тимчасового файлу , який перейменовується в файл перенаправлений , якщо команда була успішною:

for f in *.php; do
  iconv -f cp1252 -t utf-8 < $f >; $f
done
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.