AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 685644
Accepted
Marcus Müller
Marcus Müller
Asked: 2022-01-10 04:36:37 +0800 CST2022-01-10 04:36:37 +0800 CST 2022-01-10 04:36:37 +0800 CST

O que é o "comprimento" de uma string em compatíveis com Bourne shell '${#string}`?

  • 772

A partir desta discussão:

Quando eu tenho (zsh 5.8, bash 5.1.0)

var="ASCII"
echo "${var} has the length ${#var}, and is $(printf "%s" "$var"| wc -c) bytes long"

a resposta é simples: são 5 caracteres, ocupando 5 bytes.

Agora, var=Müllerrende

Müller has the length 6, and is 7 bytes long

O que sugere que o ${#}operador conta pontos de código, não bytes. Isso é um pouco obscuro no POSIX , onde eles dizem que conta "caracteres". Isso ficaria mais claro se os charatores em POSIX C não fossem octetos, normalmente.

De qualquer forma: Legal! Que bom, vendo isso LANG==en_US.utf8.

Agora,

var='??‍♀️'
echo "${var} has the length ${#var}, and is $(printf "%s" "$var"| wc -c) bytes long"
??‍♀️ has the length 5, and is 17 bytes long

Soooo, nós decompomos "Mermaid of dark skin color" no codepoint Unicode

  1. Merperson
  2. Pele escura
  3. Junção de largura zero
  4. Fêmea
  5. Imprimir imprimir o caractere anterior como emoji

Tudo bem, então estamos realmente contando pontos de código Unicode!

var="e\xcc\x81"
echo "${var} has the length ${#var}, and is $(printf "%s" "$var"| wc -c) bytes long"
é has the length 9, and is 9 bytes long

(claro, minha fonte de console decidiu que ´combina com o espaço a seguir, não o anterior e. O último estaria correto. Mas vamos deixar minha raiva sobre isso para outro momento.)

Hum, um leve "wat" está em ordem aqui.

> printf "e\xcc\x81"|wc -c
3
> printf "%s" "${var}" |wc -c
9
> echo -n ${var} |wc -c
3
> echo "${var} has the length ${#var}, and is $(printf "%s" "$var"| wc -c) bytes long"
é has the length 9, and is 9 bytes long
> printf "%s" "${var}" |xxd
00000000: 655c 7863 635c 7838 31                   e\xcc\x81

Aqui é onde eu desisto.

echo $var, echo ${var}e echo "${var}"todos "corretamente" emitem três bytes. No entanto, echo ${#var}me diz que são 9 caracteres.

Onde isso está documentado/padronizado, quais são as regras para tudo isso?

bash zsh
  • 1 1 respostas
  • 251 Views

1 respostas

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2022-01-10T05:03:25+08:002022-01-10T05:03:25+08:00

    Em shells compatíveis com POSIX (não no shell Bourne, esse recurso vem do shell Korn), ${#var}como wc -mconta o número de caracteres ¹ $vare o comportamento não é especificado se a sequência de bytes armazenada $varnão puder ser decodificada para caracteres na localidade atual.

    Os bytes são decodificados em caracteres de acordo com a localidade atual (sua LC_CTYPEcategoria). Em uma localidade que usa UTF-8 como a codificação de caracteres, a sequência 0xc3 0xa9 seria decodificada em um écaractere, enquanto em uma localidade usando ISO8859-1, que seria decodificada em ée em uma localidade usando BIG5 em 矇.

    De qualquer forma, tem pouco a ver com codepoints Unicode. Também não é o mesmo que contar o número de clusters de grafema ou a largura da string quando exibida por um terminal ou qualquer outro dispositivo de exibição.

    Dentro:

    var="e\xcc\x81"
    

    $varcontém 9 bytes e 9 caracteres: e, \, x, c, c, \, x, 8e 1.

    Alguns printf(no argumento de formato ou em argumentos para %bdiretivas de formato) e echoimplementações se expandirão \xccpara o byte 0xcc, nem todos o fazem. Por POSIX, \xem um argumento para aqueles leva a um comportamento não especificado. ( \351expande para o byte 0xe9 no printfargumento de formato e \0351em echo/ %bembora).

    Se você quiser $varconter os bytes , , em 0x65/ 0xcc/ ( e hoje em dia mais e mais shells), você faria:0x81ksh93zshbash

    var=$'e\xcc\x81'
    

    Ou você sempre pode fazer:

    var=$(printf 'e\314\201')
    

    Então, em uma localidade onde locale charmapoutputs UTF-8, $varconteria 3 bytes (como mostrado por wc -c), 2 caracteres (como mostrado por wc -mou ${#var}), 1 agrupamento de grafemas (como mostrado por GNU grep -Po '\X') geralmente exibido com largura 1 (como mostrado por GNU wc -L).

    Se a localidade no momento em que o shell foi invocado e no momento em que o código foi analisado e executado tinha UTF-8 como charset, em vários shells, você também pode fazer:

    var=$'e\u0301'
    

    Para $varconter a codificação UTF-8 dos ecaracteres e U+0301 (combinando acento agudo).

    Se o conjunto de caracteres da localidade não for UTF-8, o comportamento varia entre os shells. Além disso, se é a localidade que estava em vigor no momento em que o código foi analisado ou no momento em que o código foi executado que é levado em consideração para expandir o ponto de código Unicode em um caractere depende do shell. Você também encontrará variações de comportamento se o personagem não estiver presente no charmap do local.

    No shell Bourne, para obter o comprimento em caracteres de uma string, era necessário recorrer a outros utilitários como:

    length=`expr "x$var" : '.*' - 1` || :
    

    Ou:

    length=`printf %s "$var" | wc -m`
    

    No entanto, se você encontrar um sistema antigo o suficiente para ainda ter um shell Bourne, é provável que wcele não seja compatível -mou que não haja um printfcomando.


    ¹ O próprio POSIX não especifica o mapeamento entre sequências de bytes e caracteres, nem mesmo na localidade POSIX, apenas algumas APIs para definir e recuperar esse mapeamento ou converter sequências de bytes para sequência de caracteres ( wchar_t). Os sistemas geralmente usam conjuntos de caracteres padrão para o charmap como UTF-8, que é um formato de transformação do conjunto de caracteres definido por outro padrão ISO (ISO/IEC 10646 aka Unicode). Alguns sistemas como os GNU realmente usam os pontos de código Unicode para os wchar_tvalores, independentemente da localidade.

    • 5

relate perguntas

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve