Você pode chamar utilitários externos (veja outras respostas), mas eles tornarão seu script mais lento, e é difícil conseguir o encanamento certo.
Zsh
No zsh, você pode escrever ${#$(readlink -f /etc/fstab)}
para obter o tamanho da substituição do comando. Note que este não é o tamanho da saída do comando, é o tamanho da saída sem nenhuma nova linha.
Se você quiser o tamanho exato da saída, imprima um caractere extra de não-nova linha no final e subtraia um.
$((${#$(readlink -f /etc/fstab; echo .)} - 1))
Se o que você quer é o payload na saída do comando, então você precisa subtrair dois aqui, porque a saída de readlink -f
é o caminho canônico mais uma nova linha.
$((${#$(readlink -f /etc/fstab; echo .)} - 2))
Isso difere de ${#$(readlink -f /etc/fstab)}
no 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 um utilitário externo, pois o zsh tem uma construção interna equivalente a readlink -f
, através do modificador de histórico A
.
echo /etc/fstab(:A)
Para obter o tamanho, 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
, isso seria ${#filename:A}
.
Cascas ao estilo Bourne / POSIX
Nenhuma das camadas Bourne / POSIX puras (Bourne, ash, mksh, ksh93, bash, yash…) tem uma extensão similar que eu conheço. Se você precisar aplicar uma substituição de parâmetro à saída de uma substituição de comando ou aninhar substituições de parâmetro, use etapas sucessivas.
Você pode colocar o processamento em uma função, se quiser.
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, que faz com que uma bifurcação extra seja capaz de usar a saída da função, fazendo com que seu script fique mais lento, e
raramente há qualquer benefício 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 em command_output_length
. Usar command_output_length_sans_trailing_newlines
fornece o resultado correto somente quando o caminho canônico em si não termina em uma nova linha.
Bytes vs caracteres
${#…}
deve ser o comprimento em caracteres, não em bytes, o que faz diferença em localidades multibyte. Versões razoavelmente atualizadas de ksh93, bash e zsh calculam o comprimento em caracteres de acordo com o valor de LC_CTYPE
no momento em que a construção ${#…}
é expandida. Muitas outras shells comuns realmente não suportam localidades multibyte: a partir do traço 0.5.7, mksh 46 e posh 0.12.3, ${#…}
retorna o comprimento em bytes. Se você quiser o comprimento em caracteres de maneira confiável, use o utilitário wc
:
$(readlink -f /etc/fstab | wc -m)
Contanto que $LC_CTYPE
designe uma localidade válida, você pode ter certeza de que isso causará erros (em uma plataforma antiga ou restrita que não suporta códigos de idiomas multibyte) 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 é outra história, devido a complicações como a combinação de caracteres.)
Se você quiser o comprimento em bytes, defina LC_CTYPE=C
temporariamente ou use wc -c
em vez de wc -m
.
A contagem de bytes ou caracteres com wc
inclui qualquer nova linha no final do comando. Se você quiser o comprimento do caminho canônico em bytes, é
$(($(readlink -f /etc/fstab | wc -c) - 1))
Para obtê-lo em caracteres, subtraia 2.