Độ dài của chuỗi trong bash


427

Làm thế nào để bạn có được độ dài của một chuỗi được lưu trữ trong một biến và gán nó cho một biến khác?

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

Làm thế nào để bạn đặt một biến khác cho đầu ra 11?

Câu trả lời:


269

Độ dài chuỗi UTF-8

Ngoài câu trả lời đúng của fedorqui , tôi muốn chỉ ra sự khác biệt giữa độ dài chuỗi và độ dài byte:

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

sẽ kết xuất:

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

bạn thậm chí có thể có một cái nhìn vào các ký tự được lưu trữ:

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"

sẽ trả lời:

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

Nota: Theo nhận xét của Isabell Cowan , tôi đã thêm cài đặt $LC_ALLcùng với $LANG.

Độ dài của một đối số

Đối số hoạt động giống như các biến thông thường

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

sẽ làm việc như

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

printfCông cụ chỉnh sửa hữu ích :

Nếu bạn:

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

Không thực sự đẹp ... Đối với điều này, có một chức năng nhỏ:

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

Ngay sau đó:

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

Đáng tiếc, điều này là không hoàn hảo!

Nhưng đã để lại một số hành vi UTF-8 kỳ lạ, như ký tự cách dòng đôi, ký tự cách đều 0, độ lệch ngược và khác không thể đơn giản như ...

Hãy xem diffU8test.sh hoặc diffU8test.sh.txt để biết thêm các hạn chế.


Tôi đánh giá cao câu trả lời này, vì các hệ thống tệp áp đặt các giới hạn tên theo byte và không phải ký tự.
Gid

1
Bạn cũng có thể cần đặt LC_ALL = C và có lẽ những người khác.
Isabell Cowan

1
@ F.Hauri Nhưng, không có gì khác hơn là trên một số hệ thống, giải pháp của bạn sẽ không hoạt động, bởi vì nó để LC_ALL một mình. Nó có thể hoạt động tốt trên các bản cài đặt mặc định của Debian và các dẫn xuất của nó, nhưng trên các phần mềm khác (như Arch Linux), nó sẽ không cung cấp độ dài byte chính xác của chuỗi.
Isabell Cowan

1
cảm ơn vì đã lấy một cái gì đó đơn giản và hấp dẫn nó :)
thistleber

2
@thistlejack Tôi xin lỗi, 對不起 Đôi khi đơn giản chỉ là một ý tưởng.
F. Hauri

474

Để có được độ dài của chuỗi được lưu trữ trong một biến, hãy nói:

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

Để xác nhận nó đã được lưu chính xác, echonó:

$ echo "$size"
11

8
Với các đoạn UTF-8, bạn có thể có độ dài chuỗi độ dài byte. xem câu trả lời của tôi
F. Hauri

Bạn cũng có thể sử dụng nó trực tiếp trong các mở rộng tham số khác - ví dụ trong thử nghiệm này, tôi kiểm tra $rulenamebắt đầu bằng $RULE_PREFIXtiền tố: [ "${rulename:0:${#RULE_PREFIX}}" == "$RULE_PREFIX" ]
Thomas Guyot-Sionnest 21/07/2015

Bạn có thể vui lòng giải thích một chút các biểu thức của #myvar{#myvar}?
Lerner Zhang

1
@lerneradams xem hướng dẫn tham khảo Bash → 3.5.3 Mở rộng tham số Shell trên ${#parameter}: Độ dài tính bằng ký tự của giá trị mở rộng của tham số được thay thế .
fedorqui 'SO ngừng làm hại'

25

Bạn có thể dùng:

MYSTRING="abc123"
MYLENGTH=$(printf "%s" "$MYSTRING" | wc -c)
  • wc -c hoặc là wc --bytes cho số byte = ký tự Unicode được tính bằng 2, 3 hoặc nhiều byte.
  • wc -mhoặc wc --charscho số lượng ký tự = Các ký tự Unicode được tính đơn lẻ cho đến khi chúng sử dụng nhiều byte hơn.


3
Nghiêm túc? một đường ống, một subshell và một lệnh bên ngoài cho một cái gì đó tầm thường?
gniourf_gniourf

điều này xử lý một cái gì đó giống như mylen=$(printf "%s" "$HOME/.ssh" | wc -c)trong khi giải pháp được chấp nhận thất bại và myvar=$HOME/.sshtrước tiên bạn cần phải có .
JL Peyret

23

Tôi muốn trường hợp đơn giản nhất, cuối cùng đây là kết quả:

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

4
xin lỗi bạn đời :( Đây là bash ... cây búa bị nguyền rủa xem mọi thứ như một cái đinh, đặc biệt là ngón tay cái của bạn. 'Hãy cho tôi biết độ dài của câu này.' chứa 36 ký tự. echo '' | wc -m=> 1. Bạn cần sử dụng -n: echo -n '' | wc -m=> 0... trong trường hợp đó là một giải pháp tốt :)
AJP

1
Cảm ơn vì sự đúng đắn của bạn! Trang hướng dẫn cho biết: -n do not output the trailing newline
dmatej

17

Nếu bạn muốn sử dụng điều này với các đối số dòng lệnh hoặc hàm, hãy đảm bảo bạn sử dụng size=${#1}thay vì size=${#$1}. Cái thứ hai có thể theo bản năng hơn nhưng cú pháp không chính xác.


14
Một phần của vấn đề với "bạn không thể thực hiện <cú pháp không hợp lệ>" là, cú pháp đó không hợp lệ, không rõ người đọc nên hiểu nó có nghĩa gì. size=${#1}chắc chắn là hợp lệ
Charles Duffy

Chà, thật bất ngờ. Tôi không biết rằng # 1 là sự thay thế cho $ 1 trong trường hợp này.
Dick Guertin

16
Không phải vậy. #không thay thế $- $bên ngoài niềng răng vẫn là toán tử mở rộng. Các #toán tử chiều dài, như mọi khi.
Charles Duffy

Tôi đã sửa câu trả lời này vì đây là một mẹo hữu ích nhưng không phải là ngoại lệ đối với quy tắc - nó tuân theo chính xác quy tắc, như được chỉ ra bởi @CharlesDuffy
Zane Hooper

16

Đáp lại bài bắt đầu:

Nếu bạn muốn sử dụng điều này với các đối số dòng lệnh hoặc hàm ...

với mã:

size=${#1}

Có thể có trường hợp bạn chỉ muốn kiểm tra đối số có độ dài bằng không và không cần lưu trữ một biến. Tôi tin rằng bạn có thể sử dụng loại cú pháp này:

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

Xem GNUWooledge để biết danh sách đầy đủ hơn các biểu thức điều kiện Bash.


11

Sử dụng ví dụ của bạn được cung cấp

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.