Como contar o número de expansões de parâmetros, expansões aritméticas, etc? [fechadas]

1

Sou novo no bash scripting.

Tentando escrever um script simples que lê a entrada padrão (arquivo) e grava na saída padrão. Eu quero que o script conte o número de expansões de parâmetro / aritmética e substituições de comando.

Para entrada padrão, fiz isso até agora:

file=${1--}
while IFS= read -r line; do 
  printf '%s\n' "$line"
done < <(cat - "$file")
    
por LinuxN00b 02.12.2017 / 01:34

1 resposta

2

A maneira prática

Use apenas grep com -c flag para contar ou, melhor ainda, grep -o '<PATTERN>' | wc -l (veja a nota posteriormente no texto). Dependendo de como você deseja que sua saída se pareça e dependendo do que você deseja alcançar, há várias maneiras de configurá-la.

É claro que existem diferentes tipos de expansão de parâmetros, por isso precisamos escrever padrões diferentes para eles. Aqui eu apenas escrevi substituição de padrões, remoção de prefixo e expansão aritmética, mas você pode adaptá-los a qualquer outro.

No nível básico, podemos chamar comandos individuais da seguinte forma:

$ cat ./myscript.sh                                                         
#!/bin/bash

var="string"
echo "${var/string/thread}"
echo $((2+2))
echo $((3*2))

echo ${var#*i}
echo ${var##*i}

echo ${var%i*}
echo ${var%%i*}
$ grep -c '${.*}' myscript.sh                                               
1
$ grep -c '$((.*))' myscript.sh                                             
2

E essa é apenas a ideia básica. Você pode colocar vários padrões grep em um script com uma boa mensagem inicial. Algo como:

#!/usr/bin/env bash
printf "\nNumber of arithmetic expansions:"
grep -c '$((.*))' ""
printf "\nNumber of substitutions:"
grep -c '${.*\/.*\/.*}' ""
printf "\nNumber of prefix removals:"
grep -c '${.*[#]\{1,2\}.*}' ""

E então chame esse script como:

./count_bash_stuff.sh myscript.sh

Como alternativa, basta colocar todos os padrões no arquivo e chamar grep com -f . Obviamente, ele produzirá apenas a contagem total de todas as correspondências não individuais:

$ cat ./patterns                                                            
$((.*))
${.*\/.*\/.*}
${.*[#]\{1,2\}.*}
$ grep -c -f ./patterns ./myscript.sh                                       
5

Observação: como a steeldriver apontou no comentário abaixo desta resposta, grep é uma ferramenta de correspondência de linha, o que significa que, se houver mais de um padrão em uma linha, ele adicionará 1 para contar apenas para essa linha. A melhor abordagem seria usar -o flag com grep e canalizar a saída para wc -l . Assim, em vez disso, poderíamos fazer algo assim para a expansão aritmética:

grep -o '$((.*))' |  wc -l

O modo de shell POSIX (não tão prático)

Sim, isso é possível. É difícil, mas é possível com instruções case . Aqui só vou escrever a instrução case para expansão aritmética e remoção de prefixo mais longa. O resto depende do leitor para se adaptar e ampliar.

Novamente, lembre-se de que esta é uma prova de conceito. Observe que isso usa /bin/sh - no Ubuntu isso é compatível com POSIX /bin/dash shell, não bash .

#!/usr/bin/env sh
while IFS="" read -r line || [ -n "$line" ];
do
    case "$line" in
        # arithmetic expansion, appearing anywhere in line
        *'$(('*'))'*) arithmetic_count=$(($arithmetic_count+1));;
        *'${'*##*'}'* ) prefix_count=$((prefix_count+1));;
    esac
done < ""

echo "$arithmetic_count"
echo "$prefix_count"

E é assim:

$ ./count_shell_stuff.sh myscript.sh                                                                                                                                   
2
1

Por que isso não é tão prático que você pode perguntar? Porque escrever padrões em case pode ser um pouco desafiador e um pouco mais difícil do que em grep ou Perl . Além disso, você terá que escrever case para cada estrutura de sintaxe do shell. Com grep ou perl você pode combinar vários padrões em um. Mas, novamente, esta é apenas minha opinião pessoal. A correspondência de padrões de sequência ainda é muito possível, como demonstrei nesta pequena prova de conceito, mas não recomendaria isso como um caminho a ser seguido.

    
por Sergiy Kolodyazhnyy 02.12.2017 / 17:33