Você pode ligar para utilitários externos (veja outras respostas), mas eles tornarão seu script mais lento e é difícil acertar o encanamento.
Zsh
No zsh, você pode escrever ${#$(readlink -f /etc/fstab)}
para obter o tamanho da substituição do comando. Observe que esse não é o tamanho da saída do comando, é o comprimento da saída sem nenhuma nova linha à direita.
Se você deseja o comprimento exato da saída, produza um caractere extra não-nova linha no final e subtrai um.
$((${#$(readlink -f /etc/fstab; echo .)} - 1))
Se o que você deseja é a carga útil na saída do comando, é necessário subtrair duas aqui, porque a saída de readlink -f
é o caminho canônico mais uma nova linha.
$((${#$(readlink -f /etc/fstab; echo .)} - 2))
Isso difere do ${#$(readlink -f /etc/fstab)}
caso raro, mas possível, em que o próprio caminho canônico termina em uma nova linha.
Para este exemplo específico, você não precisa de nenhum utilitário externo, porque o zsh possui uma construção interna equivalente a ela readlink -f
, através do modificador de histórico A
.
echo /etc/fstab(:A)
Para obter o comprimento, use o modificador de histórico em uma expansão de parâmetro:
${#${:-/etc/fstab}:A}
Se você tiver o nome do arquivo em uma variável filename
, seria ${#filename:A}
.
Conchas tipo Bourne / POSIX
Nenhum dos shells Bourne / POSIX puros (Bourne, ash, mksh, ksh93, bash, yash ...) tem qualquer extensão semelhante que eu conheça. Se você precisar aplicar uma substituição de parâmetro na saída de uma substituição de comando ou aninhar substituições de parâmetro, use estágios sucessivos.
Você pode inserir o processamento em uma função, se desejar.
command_output_length_sans_trailing_newlines () {
set -- "$("$@")"
echo "${#1}"
}
ou
command_output_length () {
set -- "$("$@"; echo .)"
echo "$((${#1} - 1))"
}
mas geralmente não há benefício; exceto com ksh93, isso faz com que um fork adicional seja capaz de usar a saída da função, tornando o script mais lento e raramente há benefícios de legibilidade.
Mais uma vez, a saída de readlink -f
é o caminho canônico mais uma nova linha; se você quiser o comprimento do caminho canônico, subtraia 2 em vez de 1 pol command_output_length
. O uso command_output_length_sans_trailing_newlines
fornece o resultado certo apenas quando o caminho canônico em si não termina em uma nova linha.
Bytes vs caracteres
${#…}
deve ter o comprimento em caracteres, não em bytes, o que faz a diferença nos códigos de idioma multibyte. Versões razoavelmente atualizadas do ksh93, bash e zsh calculam o comprimento em caracteres de acordo com o valor LC_CTYPE
no momento em que a ${#…}
construção é expandida. Muitos outros shells comuns realmente não suportam localizações multibyte: a partir do traço 0.5.7, mksh 46 e posh 0.12.3, ${#…}
retorna o comprimento em bytes. Se você deseja que o tamanho dos caracteres seja confiável, use o wc
utilitário:
$(readlink -f /etc/fstab | wc -m)
Desde que $LC_CTYPE
designe um código de idioma válido, você pode ter certeza de que isso ocorrerá erro (em uma plataforma antiga ou restrita que não suporta códigos de idioma com vários bytes) ou retornará o tamanho correto em caracteres. (Para Unicode, "comprimento em caracteres" significa o número de pontos de código - o número de glifos é mais uma história, devido a complicações como a combinação de caracteres.)
Se você deseja o comprimento em bytes, defina LC_CTYPE=C
temporariamente ou use em wc -c
vez de wc -m
.
A contagem de bytes ou caracteres com wc
inclui qualquer nova linha à direita do comando. Se você deseja o comprimento do caminho canônico em bytes, é
$(($(readlink -f /etc/fstab | wc -c) - 1))
Para obtê-lo em caracteres, subtraia 2.
readlink -f /etc/fstab
é de 11 caracteres. Não esqueça a nova linha. Caso contrário, você verá/etc/fstabluser@cern:~$
quando o executou a partir de um shell.