Text processing
iconv
Convert text from one character encoding to another, such as Latin-1 or UTF-16 to UTF-8.
iconv [-f FROM] [-t TO] [OPTION...] [FILE...]
iconv re-encodes text: it reads bytes in the encoding given by -f (from) and writes the
same characters in the encoding given by -t (to). Without -f or -t it uses the current
locale's encoding, which here is UTF-8. On Linux it is part of the C library (glibc), so it is
always present.
You need it when text arrives from somewhere that does not use UTF-8: CSV exports from older
Windows software (often CP1252), legacy files in ISO-8859-1 (Latin-1), or UTF-16 files
with a byte-order mark. The symptom is usually é where é should be, or grep and sed
complaining about binary data.
iconv cannot detect the input encoding; you have to know it. file gives a reasonable guess.
When a character has no equivalent in the target encoding, conversion stops with an error
unless you ask for //TRANSLIT (approximate it) or -c (drop it).
Examples
Convert a Latin-1 file to UTF-8
Setup run before this example
printf 'caf\351 cr\350me br\373l\351e\n' > legacy.txtfile legacy.txt
iconv -f ISO-8859-1 -t UTF-8 legacy.txt
legacy.txt: ISO-8859 text café crème brûlée
file identifies the bytes as ISO-8859 text. iconv reads each accented letter as one
Latin-1 byte and writes it as the two-byte UTF-8 sequence the terminal expects.
The same character in two encodings
printf 'é\n' | od -An -t x1
printf 'é\n' | iconv -f UTF-8 -t ISO-8859-1 | od -An -t x1
c3 a9 0a e9 0a
In UTF-8, é is the two bytes c3 a9; in Latin-1 it is the single byte e9. Reading one
as the other is what produces garbled text.
Write the result to a new file
Setup run before this example
printf 'caf\351 cr\350me br\373l\351e\n' > legacy.txticonv -f ISO-8859-1 -t UTF-8 -o fixed.txt legacy.txt
file fixed.txt
fixed.txt: Unicode text, UTF-8 text
-o names the output file. Never redirect onto the input file: the shell would empty it before iconv reads it.
Windows-1252 has characters Latin-1 lacks
printf 'Price: 5\200\n' | iconv -f CP1252 -t UTF-8
Price: 5€
Byte 0x80 is the euro sign in Windows-1252 but a control character in ISO-8859-1. CSV
files saved by Windows software are usually CP1252, so choose that rather than Latin-1 when
you see € or curly quotes.
A character the target cannot represent
printf 'café\n' | iconv -f UTF-8 -t ASCII
iconv: illegal input sequence at position 3 caf
ASCII has no é. iconv writes what it converted so far (caf), reports the byte
position of the problem and exits with 1.
Approximate missing characters
echo 'Grüße – “naïve” café' | iconv -f UTF-8 -t ASCII//TRANSLIT
Grusse - "naive" cafe
//TRANSLIT replaces each character with the closest ASCII text: ü becomes u, ß
becomes ss, the en dash a hyphen and curly quotes straight ones. Handy for slugs and
file names.
Check that a file is valid UTF-8
Setup run before this example
printf 'caf\351\n' > legacy.txticonv -f UTF-8 -t UTF-8 todo.txt > /dev/null && echo "todo.txt: valid UTF-8"
iconv -f UTF-8 -t UTF-8 legacy.txt > /dev/null || echo "legacy.txt: not UTF-8"
todo.txt: valid UTF-8 iconv: illegal input sequence at position 3 legacy.txt: not UTF-8
Converting UTF-8 to UTF-8 changes nothing but fails on invalid byte sequences, which makes it a quick validity check: the exit status tells you the answer.
Drop invalid bytes
Setup run before this example
printf 'caf\351\n' > legacy.txticonv -c -f UTF-8 -t UTF-8 legacy.txt
echo "exit status: $?"
caf exit status: 1
-c silently omits characters that cannot be converted, here the stray Latin-1 byte. Note
that glibc's iconv still exits with status 1 when it had to drop something.
UTF-16 and the byte-order mark
printf 'hi\n' | iconv -f UTF-8 -t UTF-16 | od -An -t x1
printf 'hi\n' | iconv -f UTF-8 -t UTF-16LE | od -An -t x1
ff fe 68 00 69 00 0a 00 68 00 69 00 0a 00
Plain UTF-16 output starts with the byte-order mark ff fe (little-endian here) followed
by two bytes per character. Naming the byte order explicitly, UTF-16LE, leaves the mark out.
List the supported encodings
iconv -l | grep -i -m 3 '^utf-16'
UTF-16// UTF-16BE// UTF-16LE//
iconv -l prints every encoding name and alias glibc knows, over a thousand of them; grep narrows the list.
Common pitfalls
iconv -f X -t Y file > filedestroys the file. Use-o newfileand rename, or a temporary file.Guessing the source encoding wrong does not always fail: any byte sequence is valid Latin-1, so converting a UTF-8 file "from Latin-1" silently produces
é-style garbage. Check withfileand a quick look at the result.Converting an already-UTF-8 file again (double encoding) is the most common way to create mojibake. Validate with
iconv -f UTF-8 -t UTF-8first.Files from Windows may also have CRLF line endings and a UTF-8 BOM;
iconvdoes not touch either. Usetr -d '\r'orsed '1s/^\xEF\xBB\xBF//'for those.
GNU vs BSD and macOS
The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).
macOS ships a different
iconv(from libiconv) with the same-f,-t,-c,-land//TRANSLIT, but transliteration results and encoding names can differ from glibc's. The-ooption is a glibc feature; use redirection to a new file on macOS.
Options worth knowing
A selection, described in our own words. For the full list, see iconv(1) or iconv --help.
| Option | What it does |
|---|---|
-f, --from-code ENCODING | Encoding of the input. |
-t, --to-code ENCODING | Encoding of the output; append //TRANSLIT or //IGNORE to handle unconvertible characters. |
-c | Omit characters that cannot be converted. |
-o, --output FILE | Write the output to FILE. |
-l, --list | List all known encodings. |
-s, --silent | Suppress warnings. |
Related
fileGuess what kind of data a file holds by looking at its contents, not its name.trTranslate, squeeze or delete characters from standard input; for case changes, line endings and stripping characters.odDump a file's bytes as octal, hex, decimal or characters, to see exactly what it contains.sedEdit a stream of text with a script of commands, most often to substitute text or delete lines.