Comprimento da corda na festança

428

Como você obtém o comprimento de uma string armazenada em uma variável e atribui isso a outra variável?

myvar="some string"
echo ${#myvar}  
# 11

Como você define outra variável para a saída 11?

AJP
fonte

Respostas:

270

Comprimento da corda UTF-8

Além da resposta correta de fedorqui , gostaria de mostrar a diferença entre o comprimento da string e o comprimento de bytes:

myvar='Généralités'
chrlen=${#myvar}
oLang=$LANG oLcAll=$LC_ALL
LANG=C LC_ALL=C
bytlen=${#myvar}
LANG=$oLang LC_ALL=$oLcAll
printf "%s is %d char len, but %d bytes len.\n" "${myvar}" $chrlen $bytlen

renderizará:

Généralités is 11 char len, but 14 bytes len.

você pode até dar uma olhada nos caracteres armazenados:

myvar='Généralités'
chrlen=${#myvar}
oLang=$LANG oLcAll=$LC_ALL
LANG=C LC_ALL=C
bytlen=${#myvar}
printf -v myreal "%q" "$myvar"
LANG=$oLang LC_ALL=$oLcAll
printf "%s has %d chars, %d bytes: (%s).\n" "${myvar}" $chrlen $bytlen "$myreal"

Vai responder:

Généralités has 11 chars, 14 bytes: ($'G\303\251n\303\251ralit\303\251s').

Nota: De acordo com o comentário de Isabell Cowan , eu adicionei a configuração $LC_ALLjunto com $LANG.

Duração de um argumento

O argumento funciona da mesma forma que as variáveis ​​regulares

strLen() {
    local bytlen sreal oLang=$LANG oLcAll=$LC_ALL
    LANG=C LC_ALL=C
    bytlen=${#1}
    printf -v sreal %q "$1"
    LANG=$oLang LC_ALL=$oLcAll
    printf "String '%s' is %d bytes, but %d chars len: %s.\n" "$1" $bytlen ${#1} "$sreal"
}

vai funcionar como

strLen théorème
String 'théorème' is 10 bytes, but 8 chars len: $'th\303\251or\303\250me'

printfFerramenta de correção útil :

Se vocês:

for string in Généralités Language Théorème Février  "Left: ←" "Yin Yang ☯";do
    printf " - %-14s is %2d char length\n" "'$string'"  ${#string}
done

 - 'Généralités' is 11 char length
 - 'Language'     is  8 char length
 - 'Théorème'   is  8 char length
 - 'Février'     is  7 char length
 - 'Left: ←'    is  7 char length
 - 'Yin Yang ☯' is 10 char length

Não é realmente bonito ... Para isso, há uma pequena função:

strU8DiffLen () { 
    local bytlen oLang=$LANG oLcAll=$LC_ALL
    LANG=C LC_ALL=C
    bytlen=${#1}
    LANG=$oLang LC_ALL=$oLcAll
    return $(( bytlen - ${#1} ))
}

Então agora:

for string in Généralités Language Théorème Février  "Left: ←" "Yin Yang ☯";do
    strU8DiffLen "$string"
    printf " - %-$((14+$?))s is %2d chars length, but uses %2d bytes\n" \
        "'$string'" ${#string} $((${#string}+$?))
  done 

 - 'Généralités'  is 11 chars length, but uses 14 bytes
 - 'Language'     is  8 chars length, but uses  8 bytes
 - 'Théorème'     is  8 chars length, but uses 10 bytes
 - 'Février'      is  7 chars length, but uses  8 bytes
 - 'Left: ←'      is  7 chars length, but uses  9 bytes
 - 'Yin Yang ☯'   is 10 chars length, but uses 12 bytes

Infelizmente, isso não é perfeito!

Mas deixou um comportamento UTF-8 estranho, como caracteres com espaço duplo, caracteres com espaço zero, deslocamento reverso e outros que não poderiam ser tão simples ...

Dê uma olhada em diffU8test.sh ou diffU8test.sh.txt para obter mais limitações.

F. Hauri
fonte
Agradeço esta resposta, pois os sistemas de arquivos impõem limitações de nome em bytes e não em caracteres.
Gid
1
Você também pode precisar definir LC_ALL = C e talvez outros.
Isabell Cowan
1
@ F.Hauri Mas, em todo o caso, em alguns sistemas sua solução não funcionará, porque deixa LC_ALL em paz. Pode funcionar bem nas instalações padrão do Debian e seus derivados, mas em outros (como o Arch Linux) ele falhará em fornecer o tamanho correto de bytes da string.
Isabell Cowan
1
obrigado por ter tomado algo simples e convoluting it :)
thistleknot
2
@thistleknot Me desculpe, 對不起 Às vezes simples é apenas uma idéia.
F. Hauri
474

Para obter o comprimento de uma string armazenada em uma variável, diga:

myvar="some string"
size=${#myvar} 

Para confirmar se foi salvo corretamente, echoele:

$ echo "$size"
11
fedorqui 'Então pare de prejudicar'
fonte
8
Com picadas UTF-8, você pode ter um comprimento de sequência e um comprimento de bytes. veja minha resposta
F. Hauri 23/06
Você também pode usá-lo diretamente em outras expansões de parâmetros - por exemplo, neste teste, verifico que $rulenamecomeça com o $RULE_PREFIXprefixo: [ "${rulename:0:${#RULE_PREFIX}}" == "$RULE_PREFIX" ]
Thomas Guyot-Sionnest
Você poderia explicar um pouco as expressões de #myvare {#myvar}?
Lerner Zhang
1
@lerneradams ver manual de referência → 3.5.3 Shell Parâmetro Expansão Bash em ${#parameter}: O comprimento em caracteres do valor de parâmetro é expandido substituído .
fedorqui 'ASSIM, pare de prejudicar' 21/10
25

Você pode usar:

MYSTRING="abc123"
MYLENGTH=$(printf "%s" "$MYSTRING" | wc -c)
  • wc -cou wc --bytespara contagens de bytes = caracteres Unicode são contados com 2, 3 ou mais bytes.
  • wc -mou wc --charspara contagem de caracteres = caracteres Unicode são contados como únicos até que usem mais bytes.
atesina
fonte
3
A sério? um pipe, um subshell e um comando externo para algo tão trivial?
gniourf_gniourf
isso lida com algo como mylen=$(printf "%s" "$HOME/.ssh" | wc -c)considerando que a solução aceita falha e você precisa myvar=$HOME/.sshprimeiro.
JL Peyret
23

Eu queria o caso mais simples, finalmente este é um resultado:

echo -n 'Tell me the length of this sentence.' | wc -m;
36
dmatej
fonte
4
desculpe companheiro :( Este é o bash ... o martelo amaldiçoado que vê tudo como um prego, particularmente o seu polegar. 'Diga-me o comprimento desta frase.' contém 36 caracteres. echo '' | wc -m=> 1. Você precisaria usar -n: echo -n '' | wc -m=> 0... caso em que ele é uma boa solução :)
AJP
1
Obrigado pela correção! A página do manual diz: -n do not output the trailing newline
dmatej 11/11
17

Se você quiser usar isso com argumentos de linha de comando ou função, certifique-se de usar em size=${#1}vez de size=${#$1}. O segundo pode ser mais instintivo, mas é uma sintaxe incorreta.

Dick Guertin
fonte
14
Parte do problema com "você não pode fazer <sintaxe inválida>" é que, sendo essa sintaxe inválida, não está claro o que o leitor deve interpretar. size=${#1}é certamente válido.
Charles Duffy
Bem, isso é inesperado. Eu não sabia que o nº 1 era um substituto para US $ 1 neste caso.
Dick Guertin
16
Não é. #não está substituindo o $- a parte $externa do aparelho ainda é o operador de expansão. O #é o operador de comprimento, como sempre.
Charles Duffy
Eu fixo esta resposta, uma vez que é uma dica útil, mas não é uma exceção à regra - segue-se a regra exatamente como fora apontado por @CharlesDuffy
Zane Hooper
16

Em resposta ao início da postagem:

Se você deseja usar isso com argumentos de linha de comando ou função ...

com o código:

size=${#1}

Pode haver o caso em que você apenas deseja verificar um argumento de comprimento zero e não precisa armazenar uma variável. Eu acredito que você pode usar esse tipo de sintaxe:

if [ -z "$1" ]; then
    #zero length argument 
else
    #non-zero length
fi

Veja GNU e wooledge para obter uma lista mais completa de expressões condicionais do Bash.

JGFMK
fonte
11

Usando seu exemplo fornecido

#KISS (Keep it simple stupid)
size=${#myvar}
echo $size
thistleknot
fonte
9

Aqui estão algumas maneiras de calcular o comprimento da variável:

echo ${#VAR}
echo -n $VAR | wc -m
echo -n $VAR | wc -c
printf $VAR | wc -m
expr length $VAR
expr $VAR : '.*'

e para definir o resultado em outra variável, apenas atribua o comando acima com aspas a outra variável da seguinte maneira:

otherVar=`echo -n $VAR | wc -m`   
echo $otherVar

http://techopsbook.blogspot.in/2017/09/how-to-find-length-of-string-variable.html

Mukesh Shakya
fonte