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?

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.


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

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.


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

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.


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 .


11

Anhand Ihres Beispiels

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

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.