Количество символов в выводе команды оболочки

Количество символов в выводе команды оболочки

Я пишу скрипт, который должен подсчитать количество символов в выводе команды водин шаг.

Например, использование команды readlink -f /etc/fstabдолжно вернуть результат 10, поскольку вывод этой команды состоит из 10 символов.

Это уже возможно с помощью сохраненных переменных с использованием следующего кода:

variable="somestring";
echo ${#variable};
# 10

К сожалению, использование той же формулы со строкой, сгенерированной командой, не работает:

${#(readlink -f /etc/fstab)};
# bash: ${#(readlink -f /etc/fstab)}: bad substitution

Я понимаю, что это можно сделать, предварительно сохранив вывод в переменной:

variable=$(readlink -f /etc/fstab);
echo ${#variable};

Но я бы хотел убрать лишний шаг.

Возможно ли это? Предпочтительна совместимость с оболочкой Almquist (sh) с использованием только встроенных или стандартных утилит.

решение1

СGNU-выражение:

$ expr length + "$(readlink -f /etc/fstab)"
10

В +GNU есть специальная функция, exprкоторая гарантирует, что следующий аргумент будет обработан как строка, даже если это exprоператор вроде match, length, +...

Вышеуказанное удалит любой завершающий перевод строки вывода. Чтобы обойти это:

$ expr length + "$(readlink -f /etc/fstab; printf .)" - 2
10

Результат был вычтен из2потому что последняя новая строка readlinkи символ .мы добавили.

Со строкой Unicode, exprпохоже, не работает, поскольку возвращает длину строки в байтах вместо количества символов (см.строка 654)

$ LC_ALL=C.UTF-8 expr length ăaa
4

Итак, вы можете использовать:

$ printf "ăaa" | LC_ALL=C.UTF-8 wc -m
3

ПОСИКЛИ:

$ expr " $(readlink -f /etc/fstab; printf .)" : ".*" - 3
10

Пробел перед подстановкой команды предотвращает сбой команды со строкой, начинающейся с -, поэтому нам нужно вычесть 3.

решение2

Не уверен, как это сделать с помощью встроенных функций оболочки (Gnouc, хотя) но стандартные инструменты могут помочь:

  1. Вы можете использовать wc -mwhich counts characters. К сожалению, он также учитывает последний перевод строки, поэтому вам придется сначала избавиться от него:

    readlink -f /etc/fstab | tr -d '\n' | wc -m
    
  2. Конечно, вы можете использоватьawk

    readlink -f /etc/fstab | awk '{print length($0)}'
    
  3. Или Перл

    readlink -f /etc/fstab | perl -lne 'print length'
    

решение3

Я обычно делаю это так:

$ echo -n "$variable" | wc -m
10

Для выполнения команд я бы адаптировал его следующим образом:

$ echo -n "$(readlink -f /etc/fstab)" | wc -m
10

Этот подход похож на тот, который вы делали в двух шагах, за исключением того, что мы объединяем их в одну строку.

решение4

Это работает, dashно требует, чтобы целевая var была определенно пустой или неустановленной. Вот почему это на самом деледвакоманды - я явно опустошаю $lв первой:

l=;printf '%.slen is %d and result is %s\n' \
    "${l:=$(readlink -f /etc/fstab)}" "${#l}" "$l"

ВЫХОД

len is 10 and result is /etc/fstab

Это все встроенные функции оболочки ( readlinkконечно, не включая ), но вычисление их в текущей оболочке таким образом подразумевает, что вы должны выполнить присваивание до получения len, поэтому я %.sотключаю первый аргумент в printfстроке формата и просто добавляю его снова для буквального значения в конце printfсписка аргументов .

С eval:

l=$(readlink -f /etc/fstab) eval 'l=${#l}:$l'
printf %s\\n "$l"

ВЫХОД

10:/etc/fstab

Вы можете приблизиться к тому же результату, но вместо вывода в переменной в первой команде вы получаете его на stdout:

PS4='${#0}:$0' dash -cx '2>&1' "$(readlink -f /etc/fstab)"

...который пишет...

10:/etc/fstab

...в файловый дескриптор 1 без присвоения каких-либо значений каким-либо переменным в текущей оболочке.

Связанный контент