Ви можете зателефонувати за зовнішніми утилітами (див. Інші відповіді), але вони зроблять ваш сценарій повільнішим, і важко правильно встановити сантехніку.
Зш
У zsh ви можете написати, ${#$(readlink -f /etc/fstab)}
щоб отримати довжину підстановки команд. Зауважте, що це не довжина виводу команди, це довжина виводу без будь-якого зворотного нового рядка.
Якщо ви хочете точну довжину виводу, виведіть додатковий символ, що не є новим рядком, і відніміть його.
$((${#$(readlink -f /etc/fstab; echo .)} - 1))
Якщо вам потрібна корисна навантаження у висновку команди, тоді вам потрібно відняти два , оскільки вихід readlink -f
- це канонічний шлях плюс новий рядок.
$((${#$(readlink -f /etc/fstab; echo .)} - 2))
Це відрізняється від ${#$(readlink -f /etc/fstab)}
рідкісного, але можливого випадку, коли сам канонічний шлях закінчується новим рядком.
У цьому конкретному прикладі вам взагалі не потрібна зовнішня утиліта, оскільки zsh має вбудовану конструкцію, еквівалентну readlink -f
через модифікатор історії A
.
echo /etc/fstab(:A)
Щоб отримати довжину, використовуйте модифікатор історії в розширенні параметра:
${#${:-/etc/fstab}:A}
Якщо у вас є ім'я файлу в змінній filename
, це було б ${#filename:A}
.
Снаряди в стилі Борн / POSIX
Жодна з чистих оболонок Bourne / POSIX (Bourne, ash, mksh, ksh93, bash, yash…) не має подібного розширення, про яке я знаю. Якщо вам потрібно застосувати підстановку параметрів до виводу підстановки команди або до заміни параметрів гніздо, використовуйте послідовні етапи.
Ви можете залити обробку у функцію, якщо хочете.
command_output_length_sans_trailing_newlines () {
set -- "$("$@")"
echo "${#1}"
}
або
command_output_length () {
set -- "$("$@"; echo .)"
echo "$((${#1} - 1))"
}
але зазвичай користі немає; крім ksh93, це призводить до того, що додаткова вилка зможе використовувати вихід функції, тому він робить ваш сценарій повільнішим, і рідко є користь для читання.
Знову ж таки, результат readlink -f
- це канонічний шлях плюс новий рядок; якщо ви хочете довжину канонічного шляху, віднімайте 2 замість 1 дюйма command_output_length
. Використання command_output_length_sans_trailing_newlines
дає правильний результат лише тоді, коли сам канонічний шлях не закінчується новим рядком.
Байти проти символів
${#…}
повинна бути довжина в символах, а не в байтах, що змінює багатобайтові локалі. Доцільно сучасні версії ksh93, bash та zsh обчислюють довжину в символах відповідно до значення LC_CTYPE
на момент розширення ${#…}
конструкції. Багато інших поширених оболонок насправді не підтримують багатобайтові локалі: починаючи з тире 0,5,7, mksh 46 та posh 0,12,3, ${#…}
повертає довжину в байтах. Якщо ви хочете, щоб довжина символів була надійною, скористайтеся wc
утилітою:
$(readlink -f /etc/fstab | wc -m)
Поки $LC_CTYPE
позначає дійсну локаль, ви можете бути впевнені, що це або помилиться (на стародавній або обмеженій платформі, що не підтримує багатобайтові локалі), або поверне правильну довжину символів. (Для Unicode "довжина символів" означає кількість точок коду - кількість гліфів - це ще одна історія, пов’язана з ускладненнями, такими як поєднання символів.)
Якщо ви хочете довжину в байтах, встановіть LC_CTYPE=C
тимчасово або використовуйте wc -c
замість цього wc -m
.
Підрахунок байтів або символів wc
включає будь-які зворотні нові рядки з команди. Якщо ви хочете довжину канонічного шляху в байтах, це так
$(($(readlink -f /etc/fstab | wc -c) - 1))
Для отримання символів віднімайте 2.
readlink -f /etc/fstab
становить 11 символів. Не забудьте новий рядок. Інакше ви побачите,/etc/fstabluser@cern:~$
коли запустили його з оболонки.