ความยาวของสตริงเป็นทุบตี


428

คุณจะรับความยาวของสตริงที่เก็บไว้ในตัวแปรและกำหนดให้กับตัวแปรอื่นได้อย่างไร

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

คุณจะตั้งค่าตัวแปรอื่นเป็นเอาต์พุตได้11อย่างไร

คำตอบ:


270

ความยาวสตริง UTF-8

นอกจากคำตอบที่ถูกต้องของ fedorquiฉันต้องการแสดงความแตกต่างระหว่างความยาวสตริงและความยาวไบต์:

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

จะทำให้:

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

คุณสามารถดูตัวอักษรที่เก็บไว้ได้:

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"

จะตอบ:

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

หมายเหตุ:ตามความคิดเห็นของอิซาเบลแวนส์ , ฉันได้เพิ่มการตั้งค่าไปพร้อมกับ$LC_ALL$LANG

ความยาวของการโต้แย้ง

อาร์กิวเมนต์ทำงานเหมือนกับตัวแปรปกติ

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

จะทำงานเป็น

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

printfเครื่องมือแก้ไขที่มีประโยชน์:

ถ้าคุณ:

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

ไม่สวยจริงๆ... สำหรับสิ่งนี้มีฟังก์ชั่นเล็กน้อย:

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

จากนั้นตอนนี้:

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

โชคไม่ดีที่นี่ไม่สมบูรณ์แบบ!

แต่มีพฤติกรรม UTF-8 ที่แปลกประหลาดบางอย่างเช่นตัวอักษรที่เว้นระยะห่างสองตัวอักษรที่เว้นระยะแบบศูนย์การถอยกลับแบบย้อนกลับและอื่น ๆ ที่ไม่สามารถทำได้ง่าย ...

ลองดูที่diffU8test.shหรือdiffU8test.sh.txtเพื่อดูข้อ จำกัด เพิ่มเติม


ฉันขอขอบคุณคำตอบนี้เนื่องจากระบบไฟล์กำหนดข้อ จำกัด ของชื่อเป็นไบต์และไม่ใช่อักขระ
Gid

1
คุณอาจต้องตั้งค่า LC_ALL = C และอาจอื่น ๆ
Isabell Cowan

1
@ F.Hauri แต่มันก็ไม่น้อยไปกว่านั้นในบางระบบโซลูชันของคุณจะไม่ทำงานเพราะมันทิ้ง LC_ALL เพียงอย่างเดียว มันอาจทำงานได้ดีในการติดตั้ง Debian เริ่มต้นและเป็นอนุพันธ์ แต่สำหรับคนอื่น ๆ (เช่น Arch Linux) มันจะล้มเหลวในการให้ความยาวไบต์ที่ถูกต้องของสตริง
Isabell Cowan

1
ขอบคุณสำหรับการสละสิ่งที่ง่ายและ convoluting มัน :)
thistleknot

2
@thistleknot ฉันขอโทษ對不起บางครั้งเรียบง่ายเป็นเพียงความคิด
F. Hauri

474

ในการรับความยาวของสตริงที่เก็บในตัวแปรให้พูดว่า:

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

เพื่อยืนยันว่าได้รับการบันทึกอย่างถูกต้องแล้วecho:

$ echo "$size"
11

8
ด้วย UTF-8 stings คุณสามารถมีความยาวสตริงและความยาวไบต์ ดูคำตอบของฉัน
F. Hauri

คุณสามารถใช้โดยตรงในการขยายพารามิเตอร์อื่น ๆ - ตัวอย่างเช่นในการทดสอบนี้ฉันตรวจสอบว่า$rulenameเริ่มต้นด้วย$RULE_PREFIXคำนำหน้า: [ "${rulename:0:${#RULE_PREFIX}}" == "$RULE_PREFIX" ]
โทมัส Guyot-Sionnest

คุณช่วยอธิบายการแสดงออกของ#myvarและหน่อยได้{#myvar}ไหม?
Lerner Zhang

1
@lerneradams ดูทุบตีอ้างอิงคู่มือ→ 3.5.3 เชลล์พารามิเตอร์การขยายตัวใน${#parameter}: ความยาวในตัวละครของมูลค่าการขยายตัวของพารามิเตอร์แทน
fedorqui 'ดังนั้นหยุดการทำร้าย'

25

คุณสามารถใช้ได้:

MYSTRING="abc123"
MYLENGTH=$(printf "%s" "$MYSTRING" | wc -c)
  • wc -cหรือwc --bytesสำหรับจำนวนไบต์ = อักขระ Unicode จะถูกนับด้วย 2, 3 หรือมากกว่า
  • wc -mหรือwc --charsสำหรับการนับอักขระ = อักขระ Unicode จะถูกนับรวมจนกว่าพวกเขาจะใช้ไบต์มากขึ้น

4
-c สำหรับไบต์ -m สำหรับตัวอักษร gnu.org/software/coreutils/manual/html_node/wc-invocation.html pubs.opengroup.org/onlinepubs/009604499/utilities/wc.html
LLFourn

3
อย่างจริงจัง? ไปป์, subshell และคำสั่งจากภายนอกสำหรับสิ่งที่ไม่สำคัญ?
gniourf_gniourf

สิ่งนี้จัดการบางอย่างเช่นmylen=$(printf "%s" "$HOME/.ssh" | wc -c)ในขณะที่โซลูชันที่ยอมรับล้มเหลวและคุณต้องเป็นmyvar=$HOME/.sshอันดับแรก
JL Peyret

23

ฉันต้องการกรณีที่ง่ายที่สุดในที่สุดผลลัพธ์ก็คือ:

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

4
ขอโทษเพื่อน :( นี่คือทุบตี ... ค้อนสาปที่เห็นทุกอย่างโดยเฉพาะอย่างยิ่งนิ้วหัวแม่มือของคุณ 'บอกความยาวของประโยคนี้ให้ฉัน' มี 36 ตัวอักษร echo '' | wc -m=> 1คุณต้องใช้-n: echo -n '' | wc -m=> 0... ซึ่งในกรณีนี้มันเป็นคำตอบที่ดี :)
AJP

1
ขอบคุณสำหรับการแก้ไข! หน้าคู่มือพูดว่า: -n do not output the trailing newline
dmatej

17

หากคุณต้องการที่จะใช้นี้มีบรรทัดคำสั่งหรือฟังก์ชั่นการขัดแย้งให้แน่ใจว่าคุณใช้แทนsize=${#1} size=${#$1}อันที่สองอาจมีสัญชาตญาณมากกว่า แต่เป็นไวยากรณ์ที่ไม่ถูกต้อง


14
ส่วนหนึ่งของปัญหากับ "คุณไม่สามารถทำ <ไวยากรณ์ที่ไม่ถูกต้อง>" คือว่าไวยากรณ์นั้นไม่ถูกต้องมันก็ไม่ชัดเจนว่าผู้อ่านควรตีความว่ามันหมายถึงอะไร size=${#1}ถูกต้องแน่นอน
Charles Duffy

นั่นเป็นสิ่งที่คาดไม่ถึง ฉันไม่รู้ว่า # 1 เป็นสิ่งทดแทนสำหรับ $ 1 ในกรณีนี้
Dick Guertin

16
มันไม่ใช่ #ไม่ได้แทนที่$- $นอกวงเล็บปีกกายังคงเป็นผู้ประกอบการขยายตัว #เป็นผู้ดำเนินการระยะเวลาเช่นเคย
Charles Duffy

ฉันได้แก้ไขคำตอบนี้เนื่องจากเป็นเคล็ดลับที่มีประโยชน์ แต่ไม่ใช่ข้อยกเว้นของกฎ - เป็นไปตามกฎอย่างถูกต้องตามที่ระบุไว้โดย @CharlesDuffy
Zane Hooper

16

ในการตอบสนองต่อการโพสต์เริ่มต้น:

หากคุณต้องการใช้สิ่งนี้พร้อมกับบรรทัดคำสั่งหรืออาร์กิวเมนต์ของฟังก์ชัน ...

ด้วยรหัส:

size=${#1}

อาจมีกรณีที่คุณต้องการตรวจสอบอาร์กิวเมนต์ที่มีความยาวเป็นศูนย์และไม่จำเป็นต้องเก็บตัวแปร ฉันเชื่อว่าคุณสามารถใช้ไวยากรณ์ประเภทนี้:

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

ดูGNUและwooledgeสำหรับรายการที่สมบูรณ์มากขึ้นของนิพจน์เงื่อนไข Bash



9

นี่คือสองวิธีในการคำนวณความยาวของตัวแปร:

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

และการตั้งค่าผลลัพธ์ในตัวแปรอื่นเพียงกำหนดข้างบนคำสั่งด้วยเครื่องหมายคำพูดย้อนกลับเป็นตัวแปรอื่นดังต่อไปนี้:

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

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.