Lê o arquivo SQL por blocos no bash

0

Estou tentando fazer um tipo de operação de substituição de string no bash. Não é exatamente tão fácil quanto parece, então aqui está a explicação:

Digamos que você tenha um arquivo SQL com várias instruções SELECT nele. Cada bloco SELECT termina com um ponto e vírgula (; ).

Meu objetivo é pegar cada bloco separadamente e executar alguma operação com ele. No entanto, o script deve ser capaz de reconhecer esses blocos dinamicamente porque ele estará trabalhando com diferentes arquivos sql e armazenará cada bloco em uma variável (por exemplo $ 1 ), para que o bloco possa ser facilmente usado posteriormente em.

PS: Eu tenho lutado contra essa questão na semana passada e qualquer conselho seria muito apreciado. Além disso, abaixo, você pode ver alguns dos tipos de coisinhas que usei até agora:

egrep -e "^(\s|SELECT).*.[^;]\s*" test.sql

e isso

cat test.sql | awk '" "{found=0} /SELECT/{found=1} {if (found) print }'

O primeiro funciona melhor e está mais próximo do objetivo, mas não consigo encontrar uma maneira de separar e armazenar os blocos das instruções SELECT. O segundo usa uma expressão semelhante para encontrar o ponto e vírgula. Além disso, tentei dizer ao script para usar qualquer coisa entre eles como um terceiro item e, em seguida, tentar armazenar os 3 itens juntos como um todo. Não foi possível fazer isso funcionar. Instruções SELECT são multilinhas.

    
por Nikolai Uzunov 07.03.2016 / 15:59

2 respostas

0

Você pode usar um loop de leitura com um delimitador diferente de "newline". Isso faria com que o comando read em bash considerasse várias linhas como uma, desde que elas terminassem em seu delimitador.

Nota: este método não é adequado se o ponto-e-vírgula puder aparecer no arquivo dentro de comentários ou cadeias de caracteres. Isso não é um analisador - apenas um loop de leitura simples.

while read -rd ';' sql
do
    if [ "${sql#SELECT}" = "$sql" ]
    then
        echo "Not a SELECT!"
    else
        echo "This is the command I got:"
        echo ">>$sql<<"
    fi
done < test.txt 

O read -rd ';' sql vai ler a entrada até ver um ponto e vírgula. O bloco vai estar na variável $sql .

O if dentro do loop verifica se a remoção da palavra SELECT do início do texto na variável a altera - é basicamente perguntando se o texto não começa com a palavra SELECT .

Observe que read removerá os espaços em branco inicial e final em cada bloco enquanto estiver procurando por "palavras". Linhas vazias antes e depois do ponto-e-vírgula são, portanto, removidas.

Exemplo de arquivo de texto:

   SELECT *
FROM PLANTS

WHERE TYPE='BUSH'

;

INSERT INTO PLANTS (TYPE,NAME,ID)
VALUES ('TREE', 'Oak', 15)    ;   

SELECT NAME
FROM PLANTS
WHERE NAME LIKE 'O%';

Resultará na seguinte saída:

This is the command I got:
>>SELECT *
FROM PLANTS

WHERE TYPE='BUSH'<<
Not a SELECT!
This is the command I got:
>>SELECT NAME
FROM PLANTS
WHERE NAME LIKE 'O%'<<
    
por 07.03.2016 / 18:59
0
awk -v RS=";" '/SELECT/{print $0";"}'

Se um registro (em que RS é ; ) tiver a string SELECT , ele será impresso junto com ; no final.

    
por 07.03.2016 / 16:27

Tags