Если вы передаёте SQL-запросы через PowerShell и plink, наверняка сталкивались с внезапным исчезновением кавычек в командах. Это происходит из-за особенностей обработки аргументов в PowerShell, plink и удалённой оболочке. Давайте разберёмся, как сохранить синтаксис запросов без ошибок – даже если кажется, что все варианты экранирования уже перепробованы.
Почему «съедаются» кавычки: цепочка интерпретаторов
Представьте, что ваша команда проходит через три слоя интерпретации:
- PowerShell (локально)
- Plink (клиент SSH)
- Удалённая оболочка (например, bash на сервере PostgreSQL)
Каждый слой пытается обработать кавычки по-своему. Например, в исходном примере:
plink -load "FIS-S-LBX-PGS-202-a" -batch echo "select ... name = 'server_version';"
PowerShell передаёт двойные кавычки в plink, но plink «не видит» их как часть аргумента для psql. В итоге удалённый сервер получает запрос без одинарных кавычек, что ломает синтаксис SQL.
Кстати, здесь работает правило: двойные кавычки обрабатываются PowerShell, а одинарные — удалённой оболочкой. Если не «защитить» их на всех уровнях, запрос превратится в name = server_version (без кавычек), и PostgreSQL выдаст ошибку.
Решение: экранирование «вглубь»
Вариант 1 – использовать обратный слэш перед двойными кавычками и экранировать одинарные:
plink -load "FIS-S-LBX-PGS-202-a" -batch psql -c --% "select setting from pg_settings where name = 'server_version';"
Здесь:
--%
отключает парсинг PowerShell для последующих аргументов (подробнее об этом ниже);\"
сохраняет двойные кавычки для plink;\'
экранирует одинарные кавычки для удалённой оболочки.
Вариант 2 – комбинировать обратные апострофы и слэши:
plink -load "FIS-S-LBX-PGS-202-a" -batch psql -c \
"select … name = 'server_version';`"
Но это выглядит сложнее (особенно если в запросе есть переменные).
Совет: Всегда проверяйте, как команда выглядит <strong>после обработки plink</strong>. Добавьте параметр -v (verbose) к psql или посмотрите логи PostgreSQL – там отображается «сырой» запрос.
Почему не работают другие способы?
- Если использовать –% без экранирования, PowerShell передаст кавычки «как есть», но plink снимет их до передачи в psql.
- Попытка обернуть весь запрос в одинарные кавычки вызовет конфликт с синтаксисом PowerShell.
Пример рабочей команды с комментариями:
plink -load "FIS-S-LBX-PGS-202-a" -batch psql -c --% \"SELECT 'версия_сервера' AS result WHERE '1' = \'1\';\"
Здесь:
- –% отключает интерпретацию PowerShell после этого места;
- \” – экранированные двойные кавычки для plink;
- \’1\’ – экранированные одинарные кавычки для SQL.
Если всё сделано правильно, удалённый psql получит корректный запрос:
SELECT 'версия_сервера' AS result WHERE '1' = '1';
Частые ошибки и как их избежать
1. Лишние пробелы после -c:
Неправильно:
psql -c "select …"
Правильно:
powershell
psql -c"select …"
(Пробел после -c заставляет psql обрабатывать следующий аргумент как имя базы данных).
2. Непоследовательное экранирование:
Если часть кавычек экранирована, а часть нет, запрос «развалится» на удалённой стороне. Используйте единый стиль для всей команды.
3. Игнорирование версий plink/psql:
В старых версиях plink (до 0.76) могут быть баги с обработкой аргументов. Обновитесь командой:
choco upgrade putty -y
И напоследок: если команда всё равно не работает, попробуйте собрать её «снизу вверх» – сначала проверьте SQL в psql напрямую, затем добавьте plink, и только потом – обёртку в PowerShell. Это помогает локализовать слой, где происходит ошибка.
P.S. Кстати, аналогичные проблемы возникают при работе с awk
или sed
через SSH – принцип многоуровневого экранирования там тот же. Не стесняйтесь экспериментировать с кавычками и слэшами, даже если кажется, что вариантов больше нет.