Länge der Zeichenfolge in Bash

427

Wie erhält man die Länge eines in einer Variablen gespeicherten Strings und weist diese einer anderen Variablen zu?

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

Wie setzen Sie eine andere Variable auf die Ausgabe 11?

AJP
quelle

Antworten:

269

UTF-8-Stringlänge

Zusätzlich zu Fedorquis korrekter Antwort möchte ich den Unterschied zwischen Stringlänge und Bytelänge zeigen:

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

wird rendern:

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

Sie könnten sich sogar gespeicherte Zeichen ansehen:

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"

werde antworten:

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

Nota: Laut Isabell Cowans Kommentar habe ich die Einstellung $LC_ALLzusammen mit hinzugefügt $LANG.

Länge eines Arguments

Argumente funktionieren genauso wie reguläre Variablen

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

wird funktionieren als

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

Nützliches printfKorrekturwerkzeug:

Wenn du:

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

Nicht wirklich hübsch ... Dafür gibt es eine kleine Funktion:

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

Dann jetzt:

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

Leider ist das nicht perfekt!

Aber es gab ein seltsames UTF-8-Verhalten, wie Zeichen mit doppeltem Abstand, Zeichen mit null Abstand, umgekehrte Verschiebung und andere, die nicht so einfach sein konnten ...

Werfen Sie einen Blick auf diffU8test.sh oder diffU8test.sh.txt für weitere Einschränkungen.

F. Hauri
quelle
Ich schätze diese Antwort, da Dateisysteme Namensbeschränkungen in Bytes und nicht in Zeichen auferlegen.
Gid
1
Möglicherweise müssen Sie auch LC_ALL = C und möglicherweise andere festlegen.
Isabell Cowan
1
@ F.Hauri Es folgt jedoch, dass Ihre Lösung auf einigen Systemen nicht funktioniert, da LC_ALL in Ruhe gelassen wird. Bei Standardinstallationen von Debian und seinen Derivaten funktioniert es möglicherweise einwandfrei, bei anderen (wie Arch Linux) wird jedoch nicht die richtige Bytelänge der Zeichenfolge angegeben.
Isabell Cowan
1
Danke, dass
du
2
@thistleknot Es tut mir leid, 對不起 Manchmal ist einfach nur eine Idee.
F. Hauri
474

Um die Länge eines in einer Variablen gespeicherten Strings abzurufen, sagen Sie:

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

Um zu bestätigen, dass es ordnungsgemäß gespeichert wurde, gilt echoFolgendes:

$ echo "$size"
11
fedorqui 'SO hör auf zu schaden'
quelle
8
Mit UTF-8-Stings können Sie eine Zeichenfolgenlänge und eine Bytelänge haben. siehe meine Antwort
F. Hauri
Sie können es auch direkt in anderen Parametererweiterungen verwenden - zum Beispiel in diesem Test überprüfe ich, dass $rulenamemit dem $RULE_PREFIXPräfix beginnt : [ "${rulename:0:${#RULE_PREFIX}}" == "$RULE_PREFIX" ]
Thomas Guyot-Sionnest
Könnten Sie bitte die Ausdrücke von #myvarund etwas erläutern {#myvar}?
Lerner Zhang
1
@lerneradams siehe Bash-Referenzhandbuch → 3.5.3 Shell-Parametererweiterung ein ${#parameter}: Die Länge des erweiterten Parameterwerts wird in Zeichen ersetzt .
Fedorqui 'SO hör auf zu schaden'
25

Sie können verwenden:

MYSTRING="abc123"
MYLENGTH=$(printf "%s" "$MYSTRING" | wc -c)
  • wc -coder wc --bytesfür Byteanzahl = Unicode-Zeichen werden mit 2, 3 oder mehr Bytes gezählt.
  • wc -moder wc --charsfür Zeichenanzahl = Unicode-Zeichen werden einzeln gezählt, bis sie mehr Bytes verwenden.
Atesin
quelle
3
Ernsthaft? eine Pipe, eine Subshell und ein externer Befehl für etwas so Triviales?
gniourf_gniourf
Dies behandelt so etwas wie, mylen=$(printf "%s" "$HOME/.ssh" | wc -c)während die akzeptierte Lösung fehlschlägt und Sie myvar=$HOME/.sshzuerst müssen.
JL Peyret
23

Ich wollte den einfachsten Fall, schließlich ist dies ein Ergebnis:

echo -n 'Tell me the length of this sentence.' | wc -m;
36
dmatej
quelle
4
Entschuldigung Kumpel :( Dies ist Bash ... der verfluchte Hammer, der alles als Nagel sieht, besonders Ihren Daumen. "Sagen Sie mir die Länge dieses Satzes." enthält 36 Zeichen. echo '' | wc -m=> 1. Sie müssten verwenden -n: echo -n '' | wc -m=> 0... in diesem Fall ist es eine gute Lösung :)
AJP
1
Danke für die Korrektur! Handbuch Seite sagt: -n do not output the trailing newline
dmatej
17

Wenn Sie dies mit Befehlszeilen- oder Funktionsargumenten verwenden möchten, stellen Sie sicher, dass Sie size=${#1}anstelle von verwenden size=${#$1}. Die zweite ist zwar instinktiver, hat aber eine falsche Syntax.

Dick Guertin
quelle
14
Ein Teil des Problems mit "Sie können <ungültige Syntax> nicht ausführen" besteht darin, dass bei ungültiger Syntax unklar ist, was ein Leser als Bedeutung interpretieren soll. size=${#1}ist sicherlich gültig.
Charles Duffy
Das ist unerwartet. Ich wusste nicht, dass # 1 in diesem Fall ein Ersatz für $ 1 ist.
Dick Guertin
16
Ist es nicht. #ersetzt nicht die $- die $Außenseite der Klammern ist immer noch der Erweiterungsoperator. Das #ist wie immer der Längenoperator.
Charles Duffy
Ich habe diese Antwort korrigiert, da sie ein nützlicher Tipp ist, aber keine Ausnahme von der Regel darstellt - sie folgt genau der Regel, wie von @CharlesDuffy
Zane Hooper
16

Als Antwort auf den Beitrag, der beginnt:

Wenn Sie dies mit Befehlszeilen- oder Funktionsargumenten verwenden möchten ...

mit dem Code:

size=${#1}

Es kann vorkommen, dass Sie nur nach einem Argument mit der Länge Null suchen möchten und keine Variable speichern müssen. Ich glaube, Sie können diese Art von Syntax verwenden:

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

Eine vollständigere Liste der bedingten Bash-Ausdrücke finden Sie unter GNU und Wooledge .

JGFMK
quelle
11

Anhand Ihres Beispiels

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

Hier sind einige Möglichkeiten, um die Länge der Variablen zu berechnen:

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

und um das Ergebnis in einer anderen Variablen festzulegen, weisen Sie einfach den obigen Befehl mit dem Anführungszeichen wie folgt einer anderen Variablen zu:

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

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

Mukesh Shakya
quelle