Comando "wc -c" e "wc -m" in Linux


24

Ho un file di testo, il suo contenuto è:

i k k

Quando uso wc -mper contare i numeri dei caratteri su questo file, il risultato è 7 .

Domanda 1: Ma perché ho ricevuto 7, non dovrei ottenere " 6 " supponendo che conti il ​​carattere " fine linea "?

Domanda 2: come funziona esattamente wc -m?

Domanda 3: Quando uso wc -c(per contare i numeri di byte), ho lo stesso risultato di wc -m, quindi qual è il punto di avere due diverse opzioni ? Fanno esattamente lo stesso lavoro, vero? In caso contrario, qual è la differenza e come wc -cfunziona?



1
Potresti anche averne 7 se il tuo file proviene da Windows con terminazioni di linea CRLF
Chris H

Risposte:


36

Dovresti davvero avere solo 6 personaggi lì. Prova a correre

cat -A filename

Per vedere i caratteri non stampabili del tuo file. Devi avere qualcosa in più. Se creo un file come il tuo, vedo

i k k$

Hai messo uno spazio? Ciò renderebbe 7: i k k $o forse ha una nuova riga:

i k k$
$

che è anche 7

Come dici

wc -m

conta i personaggi e

wc -c

conta i byte. Se tutti i tuoi personaggi fanno parte del set di caratteri ASCII, allora ci sarà solo 1 byte per carattere in modo da ottenere lo stesso conteggio da entrambi i comandi.

Prova un file con caratteri non ASCII:

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

Aha! Più byte che caratteri ora.


3
Ho usato il comando " cat -A " e alla fine ho scoperto di avere uno spazio prima del carattere " end-of-line " ( $ ). Ecco perché ho ottenuto 7 invece di 6. Grazie, il " gatto -A " mi ha aiutato molto.
SWIIWII,

2
@SWIIWII Sì, l'ho appena aggiunto alla mia risposta, poiché pensavo che probabilmente sarebbe stato :)
Zanna,

1
anche il personaggio di Newline è stato contato. Anche se è in qualche modo non visibile, è comunque un personaggio e conta nel file come blocco di dati. A proposito, buon uso del gatto -A. Una volta si potrebbe anche usare hexdump o xxd per fare lo stesso
Sergiy Kolodyazhnyy,

@Serg sì, e cat -Alo dimostrerei anche a me . Ho aggiunto alla mia risposta, grazie :)
Zanna,

@SWIIWII inserisce il codice nei backtick `likethis`per renderlo leggibile, non renderlo in grassetto
phuclv,

2
$ locale charmap
UTF-8

Nel mio ambiente attuale, il set di caratteri è UTF-8, ovvero i caratteri sono codificati da 1 a 4 byte per carattere (anche se, poiché la definizione originale di UTF-8 consentiva il codice carattere punta fino a 0x7fffffff, la maggior parte degli strumenti riconoscerebbe UTF- Sequenze di 8 byte fino a 6 byte).

In quel set di caratteri, sono disponibili tutti i caratteri di Unicode, a aè codificato come valore di byte 65, a come 3 byte 228 185 149 e écome sequenza di due byte 195 169 per esempio.

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

Adesso:

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

Ho modificato il mio ambiente, dove il set di caratteri ora è ISO-8859-15 (sono state modificate anche altre cose come lingua, simbolo di valuta, formato della data, la raccolta di quelle impostazioni internazionali viene definita locale ). Ho bisogno di avviare un nuovo emulatore di terminale in quell'ambiente per adattare il rendering dei suoi caratteri alla nuova locale.

ISO-8859-15 è un set di caratteri a byte singolo, il che significa che ha solo 256 caratteri (in realtà anche meno di quelli effettivamente coperti). Quel particolare set di caratteri viene utilizzato per le lingue dell'Europa occidentale in quanto copre la maggior parte delle sue lingue (e il simbolo dell'euro).

Ha il acarattere con valore di byte 65 come in UTF-8 o ASCII, ha anche il écarattere (come comunemente usato in francese o spagnolo per esempio) ma con il valore di byte 233, non ha il carattere 乕.

In quell'ambiente, wc -ce wc -mdarà sempre lo stesso risultato.

In Ubuntu come sulla maggior parte dei moderni sistemi simili a Unix, il valore predefinito è solitamente UTF-8 in quanto è l'unico set di caratteri supportato (e codifica) che copre l'intera gamma Unicode.

Esistono altre codifiche di caratteri multi-byte, ma non sono così ben supportate su Ubuntu e devi passare attraverso i cerchi per essere in grado di generare un locale con quelli, e se lo fai, scoprirai che molte cose non lo fanno lavorare bene.

Pertanto, in effetti su Ubuntu, i set di caratteri sono a byte singolo o UTF-8.

Ora, qualche altra nota:

In UTF-8, non tutte le sequenze di byte formano caratteri validi. Ad esempio, tutti i caratteri UTF-8 che non sono ASCII sono formati con byte che hanno tutti l'ottavo bit impostato, ma dove solo il primo ha il settimo bit impostato.

Se si dispone di una sequenza di byte con l'ottavo bit impostato, nessuno dei quali ha il settimo bit impostato, ciò non può essere tradotto in un carattere. Ed è allora che stai iniziando ad avere problemi e incongruenze poiché il software non sa cosa farne. Per esempio:

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

wce grepnon trovi personaggi lì dentro ma:

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

bash trova 3. Quando non è in grado di mappare una sequenza di byte su un carattere, considera ogni byte un carattere.

Può diventare ancora più complicato in quanto in Unicode ci sono punti di codice che non sono validi come caratteri e alcuni che non sono caratteri e, a seconda dello strumento, la loro codifica UTF-8 può o non può essere considerata come un carattere.

Un'altra cosa da prendere in considerazione è la differenza tra personaggio e graphem e come sono resi.

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

Lì, abbiamo codificato 3 caratteri come 6 byte resi come un graphhem, perché abbiamo 3 caratteri combinati insieme (un carattere di base, un accento acuto combinato e un cerchio che racchiude).

L'implementazione GNU di wccome si trova su Ubuntu ha un -Linterruttore per dirti la larghezza di visualizzazione della linea più ampia nell'input:

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

Scoprirai anche che alcuni personaggi occupano 2 celle in quel calcolo di larghezza come il nostro personaggio dall'alto:

$ echo 乕 | wc -L
2

In conclusione: nella parola selvaggia byte, carattere e graphem non sono necessariamente gli stessi.


1

La differenza tra wc -ce wc -mè che in una locale con caratteri multibyte (diciamo, UTF8), il primo conta i byte, mentre il secondo conta i caratteri. Considera il seguente file:

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

(per coloro che non parlano UTF8, sono le lettere 'x', 'y' e 'π', seguite da una nuova riga). È lungo cinque byte:

$ wc -c dummy.txt 
5 dummy.txt

ma solo quattro caratteri:

$ wc -m dummy.txt 
4 dummy.txt

Oppure, considera anche UTF-32 dove ogni personaggio ha 4 byte.
Jörg W Mittag,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.