Panjang string dalam bash


428

Bagaimana Anda mendapatkan panjang string yang disimpan dalam variabel dan menetapkannya ke variabel lain?

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

Bagaimana Anda mengatur variabel lain ke output 11?

Jawaban:


270

Panjang string UTF-8

Selain jawaban yang benar dari fedorqui , saya ingin menunjukkan perbedaan antara panjang string dan panjang 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

akan membuat:

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

Anda bahkan dapat melihat chars yang tersimpan:

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"

akan menjawab:

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

Nota: Menurut komentar Isabell Cowan ini , saya telah menambahkan pengaturan untuk $LC_ALLbersama dengan $LANG.

Panjang argumen

Argumen berfungsi sama seperti variabel biasa

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

akan berfungsi sebagai

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

printfAlat koreksi yang berguna :

Jika kamu:

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

Tidak terlalu cantik ... Untuk ini, ada sedikit fungsi:

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

Kemudian sekarang:

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

Sayangnya, ini tidak sempurna!

Tapi ada beberapa perilaku aneh UTF-8, seperti karakter spasi ganda, karakter spasi nol, penempatan terbalik, dan lainnya yang tidak semudah itu ...

Lihatlah diffU8test.sh atau difU8test.sh.txt untuk batasan lebih lanjut.


Saya menghargai jawaban ini, karena sistem file memaksakan batasan nama dalam byte dan bukan karakter.
Gid

1
Anda mungkin juga perlu mengatur LC_ALL = C dan mungkin yang lainnya.
Isabell Cowan

1
@ F. Hauri Tetapi, tidak kurang dari itu bahwa pada beberapa sistem solusi Anda tidak akan berfungsi, karena hanya menyisakan LC_ALL. Ini mungkin berfungsi dengan baik pada instalasi default Debian dan turunannya, tetapi pada yang lain (seperti Arch Linux) akan gagal memberikan panjang byte yang benar dari string.
Isabell Cowan

1
terima kasih telah mengambil sesuatu yang sederhana dan berbelit-belit :)
thistleknot

2
@thistleknot Maafkan aku, 對不起 Kadang sederhana hanya sebuah ide.
F. Hauri

474

Untuk mendapatkan panjang string yang disimpan dalam variabel, katakan:

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

Untuk mengkonfirmasi itu disimpan dengan benar, echoitu:

$ echo "$size"
11

8
Dengan sengatan UTF-8, Anda bisa memiliki panjang string dan panjang byte. lihat jawaban saya
F. Hauri

Anda juga dapat menggunakannya secara langsung dalam parameter ekspansi lainnya - misalnya dalam tes ini saya periksa yang $rulenamedimulai dengan $RULE_PREFIXawalan: [ "${rulename:0:${#RULE_PREFIX}}" == "$RULE_PREFIX" ]
Thomas Guyot-Sionnest

Bisakah Anda jelaskan sedikit ekspresi #myvardan {#myvar}?
Lerner Zhang

1
@lerneradams lihat manual referensi Bash → 3.5.3 Ekspansi Parameter Shell aktif ${#parameter}: Panjang karakter dari nilai parameter yang diperluas diganti .
fedorqui 'SO berhenti merugikan'

25

Kamu bisa menggunakan:

MYSTRING="abc123"
MYLENGTH=$(printf "%s" "$MYSTRING" | wc -c)
  • wc -catau wc --bytesuntuk jumlah byte = Karakter Unicode dihitung dengan 2, 3 atau lebih byte.
  • wc -matau wc --charsuntuk jumlah karakter = Karakter Unicode dihitung tunggal hingga mereka menggunakan lebih banyak byte.


3
Serius? sebuah pipa, sebuah subkulit dan sebuah perintah eksternal untuk sesuatu yang sepele?
gniourf_gniourf

ini menangani sesuatu seperti mylen=$(printf "%s" "$HOME/.ssh" | wc -c)sedangkan solusi yang diterima gagal dan Anda harus myvar=$HOME/.sshterlebih dahulu.
JL Peyret

23

Saya ingin kasus paling sederhana, akhirnya ini hasilnya:

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

4
sorry mate :( Ini bash ... palu terkutuk yang melihat segalanya sebagai paku, terutama ibu jarimu. 'Ceritakan padaku panjang kalimat ini.' Berisi 36 karakter. echo '' | wc -m=> 1. Kamu harus menggunakan -n: echo -n '' | wc -m=> 0... dalam hal ini solusi yang bagus :)
AJP

1
Terima kasih atas koreksinya! Halaman manual mengatakan: -n do not output the trailing newline
dmatej

17

Jika Anda ingin menggunakan ini dengan baris perintah atau fungsi argumen, pastikan Anda menggunakan size=${#1}bukan size=${#$1}. Yang kedua mungkin lebih insting tetapi sintaksisnya salah.


14
Bagian dari masalah dengan "Anda tidak dapat melakukan <sintaks tidak valid>" adalah bahwa, sintaks tersebut tidak valid, tidak jelas apa yang harus dipahami oleh pembaca. size=${#1}tentu valid.
Charles Duffy

Yah, itu tidak terduga. Saya tidak tahu bahwa # 1 adalah pengganti $ 1 dalam kasus ini.
Dick Guertin

16
Bukan itu. #tidak menggantikan $- bagian $luar kawat gigi masih merupakan operator ekspansi. The #adalah operator panjang, seperti biasa.
Charles Duffy

Saya telah memperbaiki jawaban ini karena ini adalah tip yang berguna tetapi tidak terkecuali pada aturan - ini mengikuti aturan dengan tepat, seperti yang ditunjukkan oleh @CharlesDuffy
Zane Hooper

16

Menanggapi mulai posting:

Jika Anda ingin menggunakan ini dengan argumen baris perintah atau fungsi ...

dengan kode:

size=${#1}

Mungkin ada kasus di mana Anda hanya ingin memeriksa argumen panjang nol dan tidak perlu menyimpan variabel. Saya yakin Anda bisa menggunakan sintaks semacam ini:

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

Lihat GNU dan wooledge untuk daftar ekspresi bersyarat Bash yang lebih lengkap.


11

Menggunakan contoh Anda disediakan

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.