O núcleo da sua pergunta é a construção de uma string consistindo inteiramente de underscores com o mesmo tamanho de uma string existente. Em versões recentes do bash, ksh ou zsh, você pode construir essa string com a ${VARIABLE//PATTERN/REPLACEMENT}
construct: underlines=${word//?/_}
. Mas essa construção não existe no ksh88.
Em qualquer shell, você pode usar tr
. Implementações compatíveis com POSIX de tr
permitem escrever isto:
underlines=$(printf %s "$word" | tr -c '_' '[_*]')
Acho que o Solaris 10 tem um tr
compatível com POSIX por padrão, mas pode haver uma implementação histórica (compatível com versões anteriores do Solaris).
As implementações históricas de tr
podem não entender a sintaxe [x*]
, mas tendem a aceitar a seguinte sintaxe (que não é garantida pelo POSIX), para significar “substituir tudo o que não é uma nova linha por _
":
underlines=$(echo "$word" | tr -c '0' '_')
underlines=${underlines%_}
E aqui está um método um pouco louco que não usa nenhum loop ou programa externo e deve funcionar em qualquer shell Bourne (pelo menos desde que set -f
foi introduzido - embora a execução em um diretório vazio mitigue a falta de set -f
). Infelizmente, isso só funciona se a string não contiver espaços em branco.
set -f # turn off globbing
IFS=$word # split at any character in $word
set a $word # split $word into one word between each character, i.e. empty words
shift # remove the leading a (needed in case $word starts with -)
IFS=_
underlines=$* # join the empty words, separated with the new value of $IFS
Uma variante mais complexa lida com espaço em branco, mas apenas se não houver sequência de espaços em branco consecutivos. Eu não acho que você pode ir mais longe com esse truque, já que as sequências de caracteres em branco em IFS
são sempre reduzidas.
set -f
unset IFS; set a $0 # split at whitespace
IFS=$*; set $* # split into empty words
IFS=_; underlines=$* # collect the empty