Jak zmusić iconv do zastąpienia pliku wejściowego przekonwertowanym wyjściem?


69

Mam skrypt bash, który wylicza każdy plik * .php w katalogu i stosuje się iconvdo niego. Otrzymuje to dane wyjściowe w STDOUT.

Ponieważ dodawanie -oparametru (z mojego doświadczenia) faktycznie zapisuje pusty plik prawdopodobnie przed konwersją, w jaki sposób mogę dostosować skrypt, aby wykonał konwersję, a następnie nadpisał plik wejściowy?

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

Odpowiedzi:


76

To nie działa, ponieważ iconvnajpierw tworzy plik wyjściowy (ponieważ plik już istnieje, obcina go), a następnie zaczyna czytać plik wejściowy (który jest teraz pusty). Większość programów zachowuje się w ten sposób.

Utwórz nowy plik tymczasowy dla wyniku, a następnie przenieś go na miejsce.

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

Jeśli iconvnie ma twojej platformy -o, możesz użyć przekierowania powłoki do tego samego efektu.

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

spongeNarzędzie Colina Watsona (zawarte w moreutils Joeya Hessa ) automatyzuje to:

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

Ta odpowiedź dotyczy nie tylko iconvdowolnego programu filtrującego. Warto wspomnieć o kilku szczególnych przypadkach:

  • GNU sed i Perl -pmają -iopcję zamiany plików na miejscu.
  • Jeśli plik jest niezwykle duża, Twój filtr jest tylko modyfikację lub usunięcie niektórych części, ale nigdy dodając rzeczy (np grep, tr, sed 's/long input text/shorter text/'), i jak życia niebezpiecznie, może chcesz prawdziwie zmodyfikować plik na swoim miejscu (inne rozwiązania wymienione tutaj utworzyć nowy plik wyjściowy i przenieś go na miejsce, aby oryginalne dane pozostały niezmienione, jeśli polecenie zostanie przerwane z jakiegokolwiek powodu).

3
Nie jestem do końca pewien, czy autorstwo spongenależy przypisać wyłącznie Joeyowi Hessowi; to pakiet, moreutilsktóry zawiera sponge, ale utrzymuje, ale jeśli chodzi o pochodzenie sponge, podążając za linkami ze strony głównej moreutils, znalazłem go pierwotnie opublikowany i zasugerował włączenie Colina Watsona: „Joey pisze o braku nowych narzędzi, które pasuje do filozofii Uniksa. Moim ulubionym z takich rzeczy, które napisałem, jest sponge„(pon., 06 lutego 2006).
— imz - Ivan Zakharyaschev

3
Używam Mac OS, nie ma opcji -o w iconv, muszę zmienić `iconv -f cp1251 -t utf8 -o" $ file.new "" $ file "` toiconv -f cp1251 -t utf8 "$file" > "$file.new"
— code4j

Niektóre polecenia, na przykład sort, są dość sprytne co do -oparametru, a jeśli wykryją, że plik wyjściowy jest taki sam jak dane wejściowe, wewnętrznie zarządzają plikiem tymczasowym, więc po prostu działa.
— jesjimher

56

Alternatywą jest recodeużycie biblioteki libiconv do niektórych konwersji. Jego zachowanie polega na zamianie pliku wejściowego na dane wyjściowe, więc to zadziała:

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

Ponieważ recodejako parametr przyjmuje wiele plików wejściowych, możesz oszczędzić forpętlę:

recode cp1251..utf8 *.php

2
Dzięki, to zasługuje na więcej entuzjastów. Zastanawiam się tylko, gdzie w podręczniku wpatrzono się w 2 kropki między kodowaniami ...
— neurino,

2
„WNIOSEK często wygląda jak PRZED… PO, a PRZED i PO są kodowaniami.” W tym podręczniku naprawdę trudno jest przestrzegać wszystkich podwójnych kropek (które są częścią składni) i potrójnych kropek (co oznacza więcej tego). Rada: spróbuj info recodezamiast tego. Jest bardziej gadatliwy.
— manatwork

4

Na razie

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

działa jak marzenie


5
Na początku naprawdę myślałem, że to działa. Wygląda jednak na to, że wyjście przekraczające 32 K jest odcięte, a przy jeszcze większej ilości danych powoduje zrzuty rdzeni.
— x-yuri

1

Możesz używać Vima w trybie Ex:

ex -sc '%!iconv -f cp1251 -t utf8' -cx "$file"
  1. % wybierz wszystkie linie

  2. ! Uruchom polecenie

  3. x Zapisz i zamknij


0

Oto prosty przykład . Powinien dać ci wystarczającą ilość informacji, aby zacząć.

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

pracuje dla mnie


0

Możesz użyć find, przynajmniej to działało dla mnie w Raspbian Stretch:

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

0

Jedną z opcji jest użycie perlinterfejsu iconvi jego -itrybu do edycji w miejscu:

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

Z GNU awkmożesz także zrobić coś takiego:

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

ksh93Powłoka posiada również >;operatora dla tego, który przechowuje dane wyjściowe w pliku temp która jest zmieniana na przekierowanego pliku jeśli polecenie powiodło się:

for f in *.php; do
  iconv -f cp1252 -t utf-8 < $f >; $f
done
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.