Dize bash uzunluğu


428

Bir değişkende saklanan bir dizenin uzunluğunu nasıl elde edersiniz ve bunu başka bir değişkene nasıl atarsınız?

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

Çıktıya başka bir değişkeni nasıl ayarlarsınız 11?

Yanıtlar:


270

UTF-8 dize uzunluğu

Fedorqui'nin doğru cevabına ek olarak , dize uzunluğu ve bayt uzunluğu arasındaki farkı göstermek istiyorum:

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

oluşturacak:

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

depolanmış karakterlere bile bakabilirsiniz:

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"

cevap verecektir:

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

Nota: göre Isabell Cowan yorumuyla , ben ayar ekledik $LC_ALLbirlikte $LANG.

Tartışmanın uzunluğu

Bağımsız değişken normal değişkenlerle aynı şekilde çalışır

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"
}

olarak çalışacak

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

Yararlı printfdüzeltme aracı:

Eğer sen:

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

Gerçekten hoş değil ... Bunun için küçük bir fonksiyon var:

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

Öyleyse şimdi:

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

Ne yazık ki, bu mükemmel değil!

Ancak çift aralıklı grafikler, sıfır aralıklı grafikler, ters deplasman ve diğer kadar basit olamayacak garip UTF-8 davranışları bıraktı ...

Daha fazla sınırlama için diffU8test.sh veya diffU8test.sh.txt dosyasına göz atın .


Dosya sistemleri karakterlere değil baytlara ad sınırlamaları getirdiği için bu cevabı takdir ediyorum.
Gid

1
Ayrıca LC_ALL = C ve belki de başkalarını ayarlamanız gerekebilir.
Isabell Cowan

1
@ F.Hauri Ancak, bazı sistemlerde çözümünüz işe yaramayacaktır, çünkü LC_ALL'i yalnız bırakır. Debian ve türevlerinin varsayılan yüklemelerinde iyi çalışabilir, ancak diğerlerinde (Arch Linux gibi) dizenin doğru bayt uzunluğunu veremez.
Isabell Cowan

1
basit bir şey alarak ve kıvrım için teşekkürler :)
thistleknot

2
@thistleknot Üzgünüm, simple Bazen basit bir fikir.
F. Hauri

474

Bir değişkende saklanan bir dizenin uzunluğunu elde etmek için şunları söyleyin:

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

Düzgün kaydedildiğini onaylamak echoiçin:

$ echo "$size"
11

8
UTF-8 sokmalarıyla, bir dize uzunluğuna ve bir bayt uzunluğuna sahip olabilirsiniz. cevabımı gör
F. Hauri

Ayrıca doğrudan diğer parametre genişletmelerinde de kullanabilirsiniz - örneğin bu testte önekle $rulenamebaşlayan kontrolü yaparım $RULE_PREFIX:[ "${rulename:0:${#RULE_PREFIX}}" == "$RULE_PREFIX" ]
Thomas Guyot-Sionnest

Bir Biti ifadelerini açıklayabilir misiniz #myvarve {#myvar}?
Lerner Zhang

1
@lerneradams bkz. Bash referans el kitabı → 3.5.3 Kabuk Parametresi Genişletme açık ${#parameter}: Parametrenin genişletilmiş değerinin karakter olarak uzunluğu değiştirilir .
fedorqui 'SO' zarar vermeyi durdurun '21

25

Kullanabilirsiniz:

MYSTRING="abc123"
MYLENGTH=$(printf "%s" "$MYSTRING" | wc -c)
  • wc -cveya wc --bytesbayt sayısı için = Unicode karakterler 2, 3 veya daha fazla bayt ile sayılır.
  • wc -mveya wc --charskarakter sayıları için = Unicode karakterler daha fazla bayt kullanılana kadar tek olarak sayılır.


3
Ciddi anlamda? önemsiz bir şey için bir boru, bir alt kabuk ve harici bir komut?
gniourf_gniourf

gibi bu kolları şey mylen=$(printf "%s" "$HOME/.ssh" | wc -c)kabul çözüm oysa başarısız olursa ve gereken myvar=$HOME/.sshilk.
JL Peyret

23

En basit davayı istedim, sonunda bu bir sonuç:

echo -n 'Tell me the length of this sentence.' | wc -m;
36

4
.. Özür çiftleşmeye :( Bu bash ... bir çivi, özellikle başparmağın olarak her şeyi görür lanetli çekiç 'Bana bu cümlenin uzunluğu söyle' 36 karakter içeriyor echo '' | wc -m=> 1. Sen kullanmanız gerekir -n: echo -n '' | wc -m=> 0... bu durumda iyi bir çözüm :)
AJP

1
Düzeltme için teşekkürler! Manuel sayfa diyor: -n do not output the trailing newline
dmatej

17

Bunu komut satırı veya işlev bağımsız değişkenleriyle kullanmak istiyorsanız, size=${#1}yerine kullandığınızdan emin olun size=${#$1}. İkincisi daha içgüdüsel olabilir ancak yanlış sözdizimidir.


14
"Yapamam <geçersiz sözdizimi>" ile ilgili sorunun bir kısmı, sözdiziminin geçersiz olması, bir okuyucunun ne anlama geldiğini yorumlaması gerektiği belirsizdir. size=${#1}kesinlikle geçerlidir.
Charles Duffy

Bu beklenmedik bir şey. Bu durumda # 1'in 1 $ 'ın yerini aldığını bilmiyordum.
Dick Guertin

16
Öyle değil. #yerine geçmiyor $- $parantezlerin dışında hala genişletme operatörü var. Her #zamanki gibi uzunluk operatörüdür.
Charles Duffy

Yararlı bir ipucu olduğu için ancak kuralın bir istisnası olmadığı için bu cevabı düzelttim
Zane Hooper

16

Başlangıca yanıt olarak:

Bunu komut satırı veya işlev bağımsız değişkenleriyle kullanmak istiyorsanız ...

kodu ile:

size=${#1}

Sadece sıfır uzunluklu bir bağımsız değişken olup olmadığını kontrol etmek istediğiniz ve bir değişkeni saklamanız gerekmediği durumlar olabilir. Bu tür bir sözdizimini kullanabileceğinize inanıyorum:

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

Bash koşullu ifadelerinin daha eksiksiz bir listesi için GNU ve wooledge'e bakın .


11

Sağlanan örneğinizi kullanma

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.