[Bug 875713] [NEW] cut fails to handle correctly utf-8

Zakhar 875713 at bugs.launchpad.net
Sun Oct 16 13:23:32 UTC 2011


Public bug reported:

1) I'm using Lucid :
$ lsb_release -rd
Description:	Ubuntu 10.04.3 LTS
Release:	10.04

2) The version of coreutils (that contains the 'cut' utility)
$ apt-cache policy coreutils
coreutils:
  Installé : 7.4-2ubuntu3
  Candidat : 7.4-2ubuntu3
 Table de version :
 *** 7.4-2ubuntu3 0
        500 http://fr.archive.ubuntu.com/ubuntu/ lucid-updates/main Packages
        100 /var/lib/dpkg/status
     7.4-2ubuntu2 0
        500 http://fr.archive.ubuntu.com/ubuntu/ lucid/main Packages

3) What I expect to happen, as the man says:
$man cut
(...)
  -b, --bytes=LIST
    select only these bytes
  -c, --characters=LIST
    select only these characters
(...)

I expect a different behavior, when in 'not-1-byte' character sets such
as UTF-8, UTF-16, etc...

The same of different behavior we have with wc that says:
$man wc
(...)
  -c, --bytes
     print the byte counts
  -m, --chars
     print the character counts
(...)

So when I have on my environment :
$ env | grep 'LANG'
LANG=fr_FR.UTF-8
GDM_LANG=fr_FR.UTF-8

I can do:
$ printf '%s' 'déjà vu' | wc -c
9
$ printf '%s' 'déjà vu' | wc -m
7

That is CORRECT (with wc) because as the ENV variable says I'm using
UTF-8, the 'é' and 'à' count for 1 character but 2 bytes.


4) What happens instead: I get something wrong with 'cut'
$ printf '%s' 'déjà vu' | cut -b 1-4 | hd
00000000  64 c3 a9 6a 0a                                    |d..j.|
$ printf '%s' 'déjà vu' | cut -c 1-4 | hd
00000000  64 c3 a9 6a 0a                                    |d..j.|

(I piped it to 'hd', so that we have a better view of what's happening)

It can even be worse and give an invalid UTF-8 output
$ printf '%s' 'déjà vu' | cut -c 1-5 | hd
00000000  64 c3 a9 6a c3 0a                                 |d..j..|

That is because it 'cuts' in the middle of an UTF-8 sequence, and with the appended \n, it gives an incoherent UTF-8 sequence as we can prove:
$ printf '%s' 'déjà vu' | cut -c 1-5 | iconv -f utf-8 -t iso8859-1
d�jiconv: séquence d'échappement non permise à la position 4


We can clearly see that -b or -c makes NO difference at all... but it should, as 'wc' does, because we are in UTF-8


So either:
-Option a) the cut program is buggy, mixes the concept of 'byte' of 'character', and does things wrong when not in '1-byte' charset.
-Option b) the help/man is wrong, and there is no difference when handling bytes and chars (but then why do we have two different options!)

Note that some other GNU utilities seam to mix the concept of 'byte' and 'char', but at least the misconception is clear in the man/help, for example with 'head'
$man head
(...)
 -c, --bytes=[-]N
     print the first N bytes of each file; with the leading `-', print all but the last N bytes of each file

The -b option is unused for 'head', and yet they chosed to use -c, short
of --bytes... Looks like they meant -c as --chars, but at the last
moment decided to handle only bytes!

** Affects: coreutils (Ubuntu)
     Importance: Undecided
         Status: New

-- 
You received this bug notification because you are a member of Ubuntu
Foundations Bugs, which is subscribed to coreutils in Ubuntu.
https://bugs.launchpad.net/bugs/875713

Title:
  cut fails to handle correctly utf-8

Status in “coreutils” package in Ubuntu:
  New

Bug description:
  1) I'm using Lucid :
  $ lsb_release -rd
  Description:	Ubuntu 10.04.3 LTS
  Release:	10.04

  2) The version of coreutils (that contains the 'cut' utility)
  $ apt-cache policy coreutils
  coreutils:
    Installé : 7.4-2ubuntu3
    Candidat : 7.4-2ubuntu3
   Table de version :
   *** 7.4-2ubuntu3 0
          500 http://fr.archive.ubuntu.com/ubuntu/ lucid-updates/main Packages
          100 /var/lib/dpkg/status
       7.4-2ubuntu2 0
          500 http://fr.archive.ubuntu.com/ubuntu/ lucid/main Packages

  3) What I expect to happen, as the man says:
  $man cut
  (...)
    -b, --bytes=LIST
      select only these bytes
    -c, --characters=LIST
      select only these characters
  (...)

  I expect a different behavior, when in 'not-1-byte' character sets
  such as UTF-8, UTF-16, etc...

  The same of different behavior we have with wc that says:
  $man wc
  (...)
    -c, --bytes
       print the byte counts
    -m, --chars
       print the character counts
  (...)

  So when I have on my environment :
  $ env | grep 'LANG'
  LANG=fr_FR.UTF-8
  GDM_LANG=fr_FR.UTF-8

  I can do:
  $ printf '%s' 'déjà vu' | wc -c
  9
  $ printf '%s' 'déjà vu' | wc -m
  7

  That is CORRECT (with wc) because as the ENV variable says I'm using
  UTF-8, the 'é' and 'à' count for 1 character but 2 bytes.

  
  4) What happens instead: I get something wrong with 'cut'
  $ printf '%s' 'déjà vu' | cut -b 1-4 | hd
  00000000  64 c3 a9 6a 0a                                    |d..j.|
  $ printf '%s' 'déjà vu' | cut -c 1-4 | hd
  00000000  64 c3 a9 6a 0a                                    |d..j.|

  (I piped it to 'hd', so that we have a better view of what's
  happening)

  It can even be worse and give an invalid UTF-8 output
  $ printf '%s' 'déjà vu' | cut -c 1-5 | hd
  00000000  64 c3 a9 6a c3 0a                                 |d..j..|

  That is because it 'cuts' in the middle of an UTF-8 sequence, and with the appended \n, it gives an incoherent UTF-8 sequence as we can prove:
  $ printf '%s' 'déjà vu' | cut -c 1-5 | iconv -f utf-8 -t iso8859-1
  d�jiconv: séquence d'échappement non permise à la position 4

  
  We can clearly see that -b or -c makes NO difference at all... but it should, as 'wc' does, because we are in UTF-8

  
  So either:
  -Option a) the cut program is buggy, mixes the concept of 'byte' of 'character', and does things wrong when not in '1-byte' charset.
  -Option b) the help/man is wrong, and there is no difference when handling bytes and chars (but then why do we have two different options!)

  Note that some other GNU utilities seam to mix the concept of 'byte' and 'char', but at least the misconception is clear in the man/help, for example with 'head'
  $man head
  (...)
   -c, --bytes=[-]N
       print the first N bytes of each file; with the leading `-', print all but the last N bytes of each file

  The -b option is unused for 'head', and yet they chosed to use -c,
  short of --bytes... Looks like they meant -c as --chars, but at the
  last moment decided to handle only bytes!

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/coreutils/+bug/875713/+subscriptions




More information about the foundations-bugs mailing list