Comando "wc -c" e "wc -m" no linux

24

Eu tenho um arquivo de texto, seu conteúdo é:

i k k

Quando uso wc -mpara contar números de caracteres nesse arquivo, o resultado é 7 .

Pergunta 1: Mas por que recebi 7, não devo receber " 6 ", supondo que ele conte o caractere " fim de linha "?

Pergunta 2: Como exatamente wc -mfunciona?

Pergunta 3: Quando uso wc -c(para contar números de bytes), tenho o mesmo resultado wc -m, então qual é o sentido de ter duas opções diferentes ? Eles fazem exatamente o mesmo trabalho, não fazem? Caso contrário, qual é a diferença e como wc -cfunciona?

SWIIWII
fonte
1
Você também poderia ter conseguido 7 se você arquivo veio a partir do Windows com fins de linha CRLF
Chris H

Respostas:

36

Você realmente deve ter apenas 6 caracteres lá. Tente correr

cat -A filename

Para ver os caracteres não imprimíveis do seu arquivo. Você deve ter algo extra. Se eu criar um arquivo como o seu, vejo

i k k$

Você colocou um espaço? Isso faria 7: i k k $ou talvez tenha uma nova linha:

i k k$
$

que também é 7

Como você diz

wc -m

conta caracteres e

wc -c

conta bytes. Se todos os seus personagens fizerem parte do conjunto de caracteres ASCII, haverá apenas 1 byte por caractere, para que você obtenha a mesma contagem de ambos os comandos.

Experimente um arquivo com caracteres não ASCII:

$ echo ك > testfile
$ wc -m testfile
2 testfile
$ wc -c testfile
3 testfile

Aha! Mais bytes que caracteres agora.

Zanna
fonte
3
Eu usei o comando " cat -A " e finalmente achei que tinha um espaço antes do caractere " fim de linha " ( $ ). É por isso que eu tenho 7 em vez de 6. Obrigado, o " gato-A " ajudou muito.
SWIIWII
2
@SWIIWII Sim, acabei de adicionar isso à minha resposta, pois pensei que seria provavelmente isso:) #
Zanna
1
o caractere de nova linha também foi contado. Mesmo que não seja visível, ainda é um caractere e conta no arquivo como uma porção de dados. Bom uso do gato -A, a propósito. Uma vez também poderia usar o hexdump ou o xxd para fazer o mesmo #
Sergiy Kolodyazhnyy
@ Berg sim, e cat -Amostraria isso também. Eu adicionei a minha resposta, graças :)
Zanna
Código put @SWIIWII em backticks `likethis`para torná-lo legível, não torná-lo em negrito
phuclv
2
$ locale charmap
UTF-8

No meu ambiente atual, o conjunto de caracteres é UTF-8, ou seja, os caracteres são codificados com 1 a 4 bytes por caractere (embora, como a definição original do código de caracteres permitido UTF-8 permita pontos até 0x7fffffff, a maioria das ferramentas reconhecerá UTF- Sequências de 8 bytes de até 6 bytes).

Nesse conjunto de caracteres, todos os caracteres do Unicode estão disponíveis, a aé codificado como valor de byte 65, a como os 3 bytes 228 185 149 e écomo a sequência de dois bytes 195 169, por exemplo.

$ printf 乕 | wc -mc
  1       3
$ printf a | wc -mc
  1       1

Agora:

$ export fr_FR.iso885915@euro
$ locale charmap
ISO-8859-15

Eu modifiquei meu ambiente, onde o conjunto de caracteres agora é ISO-8859-15 (outras coisas como idioma, símbolo da moeda, formato da data também foram modificados, a coleção dessas configurações regionais é conhecida como localidade ). Preciso iniciar um novo emulador de terminal nesse ambiente para adaptar sua renderização de caracteres ao novo local.

ISO-8859-15 é um conjunto de caracteres de byte único, o que significa que ele possui apenas 256 caracteres (na verdade, menos ainda do que o que é realmente coberto). Esse conjunto de caracteres específico é usado para os idiomas da Europa Ocidental, pois abrange a maioria dos idiomas (e o símbolo do euro).

Ele possui o acaractere com valor de byte 65, como em UTF-8 ou ASCII, também possui o écaractere (como normalmente usado em francês ou espanhol, por exemplo), mas com o valor de byte 233, não possui o caractere 乕.

Nesse ambiente, wc -ce wc -msempre dará o mesmo resultado.

No Ubuntu, como nos sistemas mais modernos do tipo Unix, o padrão geralmente é UTF-8, pois é o único conjunto de caracteres (e codificação) suportado que cobre todo o intervalo Unicode.

Existem outras codificações de caracteres de vários bytes, mas elas não são tão bem suportadas no Ubuntu e você precisa passar por obstáculos para poder gerar um código de idioma com elas; caso contrário, verá que muitas coisas não trabalhe corretamente.

Portanto, no Ubuntu, os conjuntos de caracteres são de byte único ou UTF-8.

Agora, mais algumas notas:

No UTF-8, nem todas as seqüências de bytes formam caracteres válidos. Por exemplo, todos os caracteres UTF-8 que não são ASCII são formados com bytes que possuem o oitavo bit definido, mas onde apenas o primeiro possui o sétimo bit definido.

Se você tiver uma sequência de bytes com o oitavo bit definido, nenhum dos quais com o sétimo bit definido, isso não poderá ser convertido em um caractere. E é aí que você começa a ter problemas e inconsistências, pois o software não sabe o que fazer com elas. Por exemplo:

$ printf '\200\200\200' | wc -mc
      0       3
$ printf '\200\200\200' | grep -q . || echo no
no

wce grepnão encontre nenhum personagem lá, mas:

$ x=$'\200\200\200' bash -c 'echo "${#x}"'
3

bash encontra 3. Quando não pode mapear uma sequência de bytes para um caractere, considera cada byte um caractere.

Pode ficar ainda mais complicado, pois há pontos de código no Unicode que são inválidos como caracteres e alguns que não são caracteres e, dependendo da ferramenta, sua codificação UTF-8 pode ou não ser considerada como um caractere.

Outra coisa a ser levada em consideração é a diferença entre caráter e grafema, e como eles são renderizados.

$ printf 'e\u301\u20dd\n'
é⃝
$ printf 'e\u301\u20dd' | wc -mc
      3       6

Lá, codificamos 3 caracteres com 6 bytes renderizados como um graphem, porque temos 3 caracteres combinados (um caractere base, um sotaque agudo combinado e um círculo anexo).

A implementação GNU wcencontrada no Ubuntu possui uma -Lopção para informar a largura de exibição da linha mais larga na entrada:

$ printf 'e\u301\u20dd\n' | wc -L
1

Você também descobrirá que alguns caracteres ocupam 2 células nesse cálculo de largura, como nosso personagem acima:

$ echo 乕 | wc -L
2

Em conclusão: na palavra mais selvagem, byte, caractere e graphem não são necessariamente os mesmos.

Stéphane Chazelas
fonte
1

A diferença entre wc -ce wc -mé que, em um código de idioma com caracteres multibyte (digamos, UTF8), o primeiro conta bytes, enquanto o último conta caracteres. Considere o seguinte arquivo:

$ hexdump -C dummy.txt 
00000000  78 79 cf 80 0a                                    |xy...|

(para quem não fala UTF8, são as letras 'x', 'y' e 'π', seguidas por uma nova linha). Tem cinco bytes de comprimento:

$ wc -c dummy.txt 
5 dummy.txt

mas apenas quatro caracteres:

$ wc -m dummy.txt 
4 dummy.txt
Marca
fonte
Ou considere até UTF-32, onde cada caractere possui 4 bytes.
Jörg W Mittag