Довжина струни в басі


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, щоб отримати додаткові обмеження.


Я ціную цю відповідь, оскільки файлові системи накладають обмеження на ім'я в байтах, а не символи.
Гід

1
Вам також може знадобитися встановити LC_ALL = C і, можливо, інші.
Ізабелл Коуан

1
@ F.Hauri Але все ж випливає, що в деяких системах ваше рішення не працюватиме, оскільки він залишає LC_ALL в спокої. Це може спрацювати при встановленні за замовчуванням Debian і його похідних, але для інших (наприклад, Arch Linux) він не зможе дати правильну довжину байта рядка.
Ізабелл Коуан

1
дякую за те, що ви взяли щось просте і
перекрутили

2
@thistleknot Вибачте, 對不起 Іноді просто - це лише ідея.
Ф. Хаурі

474

Щоб отримати довжину рядка, що зберігається у змінній, скажіть:

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

Щоб підтвердити правильність збереження, echoце:

$ echo "$size"
11

8
Завдяки UTF-8, ви можете мати довжину рядка та довжину байтів. дивіться мою відповідь
Ф. Хаурі

Ви також можете використовувати його безпосередньо в інших розширеннях параметрів - наприклад, у цьому тесті я перевіряю, що $rulenameпочинається з $RULE_PREFIXпрефікса: [ "${rulename:0:${#RULE_PREFIX}}" == "$RULE_PREFIX" ]
Thomas Guyot-Sionnest

Не могли б ви пояснити трохи виразів #myvarта {#myvar}?
Лернер Чжан

1
@lerneradams див. посібник користувача Bash → 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 вважаються одиничними, поки вони не використовують більше байтів.


3
Серйозно? труба, нижня оболонка та зовнішня команда для чогось тривіального?
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}безумовно, діє.
Чарльз Даффі

Ну, це несподівано. Я не знав, що №1 в цьому випадку замінив 1 долар.
Дік Гертін

16
Це не так. #не замінює $- $зовнішні дужки все ще є оператором розширення. Оператор #довжини, як завжди.
Чарльз Даффі

Я вирішив цю відповідь, оскільки це корисна порада, але не виняток із правила - вона точно слідує правилу, як вказувало @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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.