O utilitário expr
analisa seus argumentos como uma expressão. Os operadores devem aparecer como argumentos independentes.
expr "$j" : '.*'
Acima, expr
recebe 4 argumentos: expr
, o conteúdo de $j
, :
e .*
. Supondo que o conteúdo de $j
não seja (
ou !
(ou coisas como length
com algumas implementações), expr
sob isso, como o operador de correspondência de padrões :
aplicado ao conteúdo de $j
.
Para torná-lo mais robusto, você deseja:
expr " $j" : '.*' - 1
(o segundo argumento que começa com um espaço não pode ser reconhecido como um operador expr de modo que funcione em torno dos problemas mencionados acima).
com
expr $j:'.*'
Isso seria dois argumentos ( expr
e o conteúdo de $j
seguido por :.*
(assumindo que $j
não contém caracteres em branco ou curinga, veja abaixo)). Como expr
só vê um argumento (ao lado do nome do comando), não há nenhuma operação solicitada, isso é apenas um argumento de string que expr
simplesmente ecoa de volta.
Agora, há vários outros problemas com seu código:
Expansão de variável e substituição de comando ( $((...))
ou a forma '...'
de uso em desuso que você usa), quando não referenciado, passar split+glob
. Você deseja que a parte split
da parte 'cat $1'
(deveria ter sido $(cat < "$1")
) a divida em palavras, mas não a parte glob, pois de outra forma expandiria *
palavras por exemplo para a lista de arquivos no diretório atual; e todas as outras expansões de variáveis devem ser citadas (não necessárias em atribuições, mas as citações não prejudicam).
Além disso, você não pode usar echo
para dados arbitrários .
Então deve ser:
w=0 c=0
set -f # disable glob
for i in $(cat < "$1"); do
printf '%s\n' "$i"
w="$((w + 1))"
c="$(expr " $i" : '.*' + "$c" - 1)"
done