Я пытался выполнить операцию замены строки в bash. Это не совсем так просто, как кажется, поэтому вот объяснение:
Допустим, у вас есть SQL-файл с несколькими операторами SELECT. Каждый блок SELECT заканчивается точкой с запятой (;).
Моя цель - взять каждый блок отдельно и выполнить с ним некоторую операцию. Однако скрипт должен уметь распознавать эти блоки динамически, поскольку он будет работать с разными sql файлами, и сохранять каждый блок в переменную (например, $1), чтобы блок можно было легко использовать позже.
PS Я бился над этой проблемой в течение последней недели, и любой совет будет очень признателен. Кроме того, ниже вы можете увидеть некоторые из regex-типов, которые я использовал до сих пор:
egrep -e "^(\s|SELECT).*.[^;]\s*" test.sql
и это
cat test.sql | awk '" "{found=0} /SELECT/{found=1} {if (found) print }'
Первый вариант работает лучше всего и ближе всего к цели, но я не могу найти способ разделить и сохранить блоки операторов SELECT. Второй вариант использует аналогичное выражение для поиска точки с запятой. В дополнение к этому я попытался указать сценарию использовать все, что находится между ними, в качестве третьего элемента, а затем попытаться сохранить эти три элемента вместе как единое целое. Однако это не сработало. Операторы SELECT являются многострочными.
Вы можете использовать цикл чтения с разделителем, отличным от символа новой строки. Это заставит команду read
в bash
рассматривать несколько строк как одну, при условии, что они заканчиваются вашим разделителем.
Примечание: этот метод не подходит, если точка с запятой может стоять в файле внутри комментариев или строк. Это не парсер, а простой цикл чтения.
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
читается как -rd ';' sql
будет читать ввод, пока не увидит точку с запятой. Блок будет в переменной $ sql
.
if
внутри цикла проверяет, изменяет ли удаление слова SELECT
из начала текста в переменной его - в основном он спрашивает, не начинается ли текст со слова ВЫБРАТЬ
.
Обратите внимание, что read
удалит начальные и конечные пробелы в каждом блоке при поиске «слов». Поэтому пустые строки до и после точки с запятой удаляются.
Пример текстового файла:
SELECT *
FROM PLANTS
WHERE TYPE='BUSH'
;
INSERT INTO PLANTS (TYPE,NAME,ID)
VALUES ('TREE', 'Oak', 15) ;
SELECT NAME
FROM PLANTS
WHERE NAME LIKE 'O%';
Результатом будет следующий вывод:
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%'<<
awk -v RS=";" '/SELECT/{print $0";"}'
Если запись (где RS
- ;
) имеет строку SELECT
, то она будет напечатана вместе с ;
в конце.