Espaço extra com o número da linha contada?

3

Eu conto o número de linhas do meu arquivo com este comando no OSX:

nl=$(wc -l < ~/myfile.txt)

Digamos que nl seja 100. Agora, desejo usar o resultado nl em outro comando, mas, estranhamente,

echo 1-$nl

me dá 1- 100 em vez de 1-100 .

Demo

cv me$ nl=$(wc -l < ~/Desktop/cap.xlsx)
cv me$ echo $nl
104
cv me$ echo 1-$nl
1- 104

Por que isso acontece? Como posso obter 1-100 ?

    
por Sibbs Gambling 27.05.2015 / 17:45

4 respostas

4

Como POSIX definido, a saída de wc deve conter uma entrada para cada arquivo de entrada do formulário:

"%d %d %d %s\n", <newlines>, <words>, <bytes>, <file>

Mas o formato do arquivo de saída pseudo printf() string difere da versão do System V de wc :

"%7d%7d%7d %s\n"

O POSIX não exigiu que os espaços iniciais fossem adicionados, portanto, é livre para que a implementação faça o que quiser. Existem implementações diferentes de wc , pelo menos com OSX e wc do repositório de ferramentas de herança, ele acrescentou espaços iniciais à saída.

$ /usr/5bin/wc -l /tmp/file
      3  /tmp/file

O GNU wc também adiciona espaços iniciais ao ler o padrão em e sem opções:

$ cat file | wc
  5       5      65

Para remover todos os espaços iniciais, no shell POSIX:

set -f
set -- $nl
nl=$1
set +f

Observe que essa abordagem pressupõe que a variável contenha apenas espaços iniciais ou finais, sem espaços no meio, como a b .

    
por 27.05.2015 / 18:11
4

wc implementações podem produzir espaços iniciais; isso também pode depender se (e quantas) opções são usadas (por exemplo, o GNU wc não produzirá espaços se, como no seu caso, exatamente uma opção for usada). Esses espaços são retidos na atribuição nl=$(...) . Para remover os espaços, como solução alternativa, você poderia usar um dos seguintes:

nl=$(wc -l < ~/myfile.txt | awk '{print $1}')

ou

nl=$(awk 'END{print NR}' ~/myfile.txt)

ou

nl=$(wc -l < ~/Desktop/cap.xlsx)
nl=$(echo $nl)

ou (mas veja o comentário de @ cuonglm abaixo para a versão de heirloom de wc )

nl=$(wc -l < ~/Desktop/cap.xlsx)
nl=${nl##* }
    
por 27.05.2015 / 18:05
1

Solução mais simples (no bash ou em qualquer outro shell POSIX):

nl=$(wc -l < ~/myfile.txt)
nl=$(($nl))

$((...)) no padrão sh é para expansão aritmética, então o resultado sempre será apenas o próprio número. Observe que, se wc -l não produzir saída (como quando o arquivo não puder ser lido), isso gerará 0 em vez de uma string vazia.

$((nl)) também funcionaria em bash , mas não é garantido pelo POSIX, pois $nl não contém uma constante numérica e, na prática, não funciona em yash , por exemplo.

Você também pode fazer tudo de uma vez com:

nl=$(($(wc -l < ~/myfile.txt)))

Qual tem o benefício de preservar o status de saída de wc .

    
por 09.09.2018 / 18:14
1

Como uma alternativa sem o problema dos espaços (POSIX):

$ sed -n '$=' ~/myfile.txt

Capturado em uma variável:

$ nl=$(sed -n '$=' ~/myfile.txt)
$ echo "1-$nl-"
1-100-

Observe que o sed conta a última linha, mesmo que não termine em um caractere de nova linha (como deveria em um arquivo de texto formatado corretamente). Mais geralmente, o sed pode não conseguir imprimir o número de caracteres de nova linha em arquivos que não são de texto.

Outra alternativa:

$ nl=$(grep -v . ~/myfile.txt | tr '\n' 'x')
$ echo "1-${#nl}"
1-100

Note que o grep também imprime caracteres inválidos (além de novas linhas) na localidade usada.

    
por 10.09.2018 / 03:52

Tags