Como tratar os números que começam com zeros como um número inteiro decimal

3

A entrada seria o nome do arquivo, como segue:

A-B-000001-C
A-B-000002-C
.....
.....
A-B-999999-C

Todo o arquivo deve ser seqüencial. Eu quero encontrar nomes de arquivos seqüenciais em falta. Para isso, estou separando o número de sequência de 6 dígitos usando awk e usando grep com expressão regular para verificar se o arquivo está presente no diretório.

'ls|grep "A-B-${sequencenumber}-.*"|wc -l'

mas o script de shell não está tratando o número como decimal e se eu forçar o número a ser tratado como decimal usando 10 # $ sequencenumber então ele removerá os zeros anteriores que são necessários para pesquisar o arquivo.

Existe alguma maneira de contornar isso?

    
por Milon Corleone 10.01.2016 / 12:05

3 respostas

4

Os shells tratam números com zeros à esquerda como octal. Um truque para contornar isso é manipular apenas números com um dígito à esquerda extra diferente de zero, por exemplo conte de 1000001 a 1999999. Para obter o número desejado com zeros à esquerda, retire o primeiro 1 com uma operação de string.

n=1000001
while [ $n -le 1999999 ]; do
  digits=${n#1}
  set "A-B-$digits-."*
  if [ -e "$1" ]; then echo "${digits}: $#"; fi
  n=$((n+1))
done

Este método é portátil para todos os shells do POSIX e evita a criação de um subprocesso para os cálculos, o que pode torná-lo mais rápido (mas um milhão de iterações provavelmente serão lentas de qualquer maneira, shells não são as melhores no desempenho).

No script acima, em vez do comando complexo e lento envolvendo ls e wc para contar arquivos correspondentes, eu uso construções internas do shell: set A-B-$digits-.* define os parâmetros posicionais para a lista de arquivos correspondentes, e a linha a seguir imprime o número de correspondências ( $# ) se houver pelo menos uma correspondência (se não houver correspondência, o padrão permanecerá inalterado e, portanto, [ -e "$1" ] será [ -e "A-B-$digits-.*" ] , que é falso).

    
por 11.01.2016 / 01:43
3

Você pode usar o utilitário printf para preenchimento, por exemplo,

$(ls|grep "A-B-$(printf '%06d' $sequencenumber)-.*"|wc -l)

Dois pontos:

  • enquanto tanto 'foo' quanto $(foo) são padrão , os locais aninhados tendem para não ser tão portátil
  • o utilitário printf é útil para mais do que apenas preenchimento.
por 10.01.2016 / 12:41
3

Usar wc -l não produzirá o resultado correto se o nome de seus arquivos contiver nova linha.

Com bash e zsh , você pode usar a expansão de chaves:

for n in {000001..999999}; do
  f=A-B-$n-C
  [ -f "$f" ] || printf '%s missing\n' "$f"
done

ksh93 com braceexpand opção ativar:

for n in {1..999999%06d}; do
  : the code above
done

Em ksh e zsh , você pode fazer:

typeset -Z6 i=1
max=999999
while [ "$i" -le "$max" ]; do
  f=A-B-$i-C
  [ -f "$f" ] || printf '%s missing\n' "$f"
  : "$((i+=1))"
done

POSIXly:

min=1
max=999999
while [ "$min" -le "$max" ]; do
  f=$(printf "A-B-%0${#max}d-C" "$min")
  [ -f "$f" ] || printf '%s missing\n' "$f"
  : "$((min+=1))"
done
    
por 10.01.2016 / 12:43