Erro ao contar caracteres em um arquivo

1

Eu tenho um código-fonte para encontrar várias palavras e caracteres em um arquivo:

#!/bin/bash
w=0
cc=0
for i in 'cat $1'
do
j=$i
echo $j
w=$(($w+1))
c='expr $j:'.*''
cc=$(($cc+$c))
done
echo "no of characters"  $cc
echo "no of words" $w

Mas quando eu o executo no terminal, a seguinte mensagem de erro é exibida ^ ./countWordChar 1.c Olá ./countWordChar: linha 10: 0+hello:.* : erro de sintaxe na expressão (token de erro é ":.*" ) nenhum dos caracteres 0 não de palavras 1

A décima linha no código é cc=$(($cc+$c)) . Aparentemente, o valor da variável c não é um número de caracteres de uma palavra, mas a própria palavra.

E meu conteúdo do arquivo 1.c é assim:

hello world
hello

O que há de errado no código?

PS. Eu sei que existem comandos embutidos para contar caracteres em um arquivo, mas devo usar o código anterior de acordo com a minha tarefa.

    
por Stranger 29.05.2016 / 11:15

2 respostas

1

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
    
por 29.05.2016 / 11:37
0

Com expr $j:'.*' , o comando expr está recebendo um (1) argumento.
O comando expr não conseguiu entender isso.

O comando expr precisa de cada argumento claramente separado:

expr "$j" ":" '.*'

Serão três (3) argumentos dados ao comando expr . As cotas " em torno de : não são realmente necessárias. E é melhor usar um espaço antes da string em $j para evitar algumas interpretações erradas, como esta:

expr " $j" : '.*'

Isso tornaria seu script semelhante a este:

#!/bin/dash
w=0    cc=0
for i in 'cat $1'; do
    echo "$j"
    w=$(($w+1))
    c='expr " $i" : '.*''
    cc=$((cc+c))
done
echo "no of characters"  $cc
echo "no of words" $w

Mas isso é mais um script de traço do que um script bash (é assim que você marcou sua pergunta).
Um script bash simplificado ficará assim:

#!/bin/bash
w=0    cc=0
for i in $(< $1)
do
    ((w++))
    cc=((cc+${#i}))
done
echo "no of characters"  "$cc"
echo "no of words" "$w"

O $(< $1) é equivalente a $(cat $1) , mas um pouco mais rápido. Para incrementar w, is é mais curto para usar w++ . E para contar o número de caracteres, podemos usar o comprimento de $i como ${#i} .

Ou ainda mais curto:

#!/bin/bash
w=0    cc=0
for i in $(< $1)
do  (( w++ , cc += ${#i} ))
done
printf "no of characters %s\nno of words %s\n"  "$cc" "$w"

Usando o operador bash (de 2.04-devel e superior) comma , e usando cc += ${#i} como o equivalente a cc = cc + ${#i} .

    
por 30.05.2016 / 06:39