Вы можете вызвать внешние утилиты (см. Другие ответы), но они сделают ваш скрипт медленнее, и сложно правильно разобраться с сантехникой.
Zsh
В 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}
.
Оболочки в стиле Bourne / 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
в момент раскрытия ${#…}
конструкции. Многие другие распространенные оболочки в действительности не поддерживают многобайтовые локали: по состоянию на dash 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:~$
когда вы запускаете его из оболочки.