Передача Json в Python из сценария PowerShell - PullRequest
1 голос
/ 06 мая 2020

Я безуспешно пытаюсь передать строку Json в сценарий Python с использованием сценария PowerShell (.ps1) для автоматизации этой задачи.

spark-submit `
--driver-memory 8g `
--master local[*] `
--conf spark.driver.bindAddress=127.0.0.1 `
--packages mysql:mysql-connector-java:6.0.6,org.elasticsearch:elasticsearch-spark-20_2.11:7.0.0 `
--py-files build/dependencies.zip build/main.py `
$param

Когда $param='{ \"\"job_start\"\": \"\"jdbc:mysql://127.0.0.1:3307/test\"\"}' работает нормально, python получает действительную строку JSON и правильно анализирует.

Когда я использую символ & как $param='{ \"\"job_start\"\": \"\"jdbc:mysql://127.0.0.1:3307/test&serverTimezone=UTC&autoReconnect=true&useSSL=false\"\"}', строка печатается как { "job_start": \jdbc:mysql://127.0.0.1:3307/test?, а остальная часть строки повторно преобразовывается как другие команды.

'serverTimezone' is not recognized as an internal or external command
'autoReconnect' is not recognized as an internal or external command
'useSSL' is not recognized as an internal or external command

\"\" необходимо для поддержки двойных кавычек в сценарии Python, не уверен, зачем нужны две экранированные двойные кавычки.

ОБНОВЛЕНИЕ:

Теперь у меня проблемы с символом !, я не могу избежать этого символа даже с ^ or \.

# Only "" doesn't work
$param='{\"\"job_start\"\": \"\"jdbc:mysql://127.0.0.1:3307/test^&serverTimezone=UTC\"\", \"\"password\"\": \"\"testpassword^!123\"\"}'

spark-submit.cmd `
--driver-memory 8g `
--master local[*] `
--conf spark.driver.bindAddress=127.0.0.1 `
--packages mysql:mysql-connector-java:6.0.6,org.elasticsearch:elasticsearch-spark-20_2.11:7.0.0 `
--py-files build/dependencies.zip build/main.py `
$param

# OUTPUT: misses the ! character
{"job_start": "jdbc:mysql://127.0.0.1:3307/test&serverTimezone=UTC", "password": "testpassword123"}

Всем спасибо.

Ответы [ 2 ]

1 голос
/ 06 мая 2020

tl; dr

Примечание. Следующее не решает проблему c OP (причина которой пока неизвестна), но мы надеемся содержит информацию, представляющую общий интерес.

# Use "" to escape " and - in case of delayed expansion - ^! to escape !
$param = '{ ""job_start"": ""jdbc:mysql://127.0.0.1:3307/test&serverTimezone=UTC&more^!"" }'
  • Существуют высокопрофильные утилиты (CLI), такие как az (Azure), основанные на Python , но на Windows используйте вспомогательный командный файл в качестве исполняемого файла, который просто передает аргументы сценарию Python.
    • Используйте Get-Command az, например, чтобы узнать полное имя исполняемого файла; пакетные файлы, которые обрабатываются cmd.exe, устаревшим командным процессором, имеют расширение имени файла .cmd или .bat
  • Чтобы предотвратить вызовы такого командного файла из взлом, двойные кавычки, встроенные в аргументы, переданные из PowerShell, должны быть экранированы как ""
  • Дополнительно, но только в том случае, если setlocal enabledelayedexpansion действует в данном целевом пакетном файле или если ваш компьютер настроен на использование отложенного расширения по умолчанию , для все командные файлы:
    • ! символы должны быть экранированы как ^!, который, однако, эффективен только в том случае, если cmd.exe учитывает ! часть строки с двойными кавычками.

Похоже, что у нас есть сочетание двух проблем :

  • A PowerShell проблема с " символами. встроенный в аргументы, передаваемые внешним программам :

    • В идеальном мире передача JSON текста, такого как '{ "foo": "bar" }', в внешняя программа будет работать как есть , но из-за неработающей обработки PowerShell встроенных двойных кавычек , то есть недостаточно , и " символов. необходимо дополнительно экранировать для программы target либо как \" (которое поддерживает большинство программ), либо, в случае cmd.exe (см. ниже), как "", который Python, к счастью, тоже распознает: '{ ""foo"": ""bar"" }'
  • Ограничения передачи аргументов и экранирования в cmd.exe пакете files :

    • Похоже, spark-submit - это вспомогательный пакетный файл (.cmd или .bat), который передает аргументы через в сценарий Python.

    • Проблема в том, что , если вы используете \" для экранирования встроенного ", cmd.exe не 'не распознает их как экранированный , что заставляет его рассматривать символы & без кавычек , и поэтому они интерпретируются как метасимволы оболочки , т.е. как символы со специальной функцией синтаксиса c (в данном случае последовательность команд).

    • Дополнительно и только если setlocal enabledelayedexpansion действует в для данного командного файла любые буквальные ! символы в аргументах требуют дополнительной обработки:

      • Если cmd.exe считает, что ! является частью аргумент без кавычек , вы не можете избежать ! вообще.

      • Внутри аргумента в кавычках (что неизменно означает "..." в cmd.exe) , вы должны экранировать буквальный ! как ^!.

        • Обратите внимание, что это требование является инверсией того, как все другие метасимволы должны быть экранированы (что требует ^, когда без кавычек , но не внутри "...").

        • К сожалению, вам необходимо знать детали реализации целевого пакетного файла - использует ли он setlocal enabledelayedexpansion или нет - чтобы правильно сформулировать ваши аргументы.

        • То же применимо, если ваш компьютер настроен на использование отложенного расширения по умолчанию , для все командные файлы (и в интерактивном режиме), что не является обычным и не рекомендуется. Чтобы проверить, настроен ли данный компьютер таким образом, проверьте выходные данные следующей команды для DelayedExpansion : 1: если выходных данных нет вообще, отложенное раскрытие отключено; если есть 1 или 2 выхода, отложенное расширение включено по умолчанию, если первый или только выводит отчеты DelayedExpansion : 1.

 Get-ItemProperty -EA Ignore 'registry::HKEY_CURRENT_USER\Software\Microsoft\Command Processor', 'registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor' DelayedExpansion

Обходной путь :

  • Поскольку вы технически вызываете командный файл, используйте "" чтобы избежать буквального " символов. внутри строки PowerShell в одинарных кавычках ('...').

  • Если вы знаете, что целевой пакетный файл использует setlocal enabledelayedexpansion или , если ваш компьютер настроен на использовать отложенное раскрытие по умолчанию , экранировать ! символы как ^!

    • Обратите внимание, что это эффективно, только если cmd.exe учитывает ! часть двойного- строка в кавычках.

Поэтому (обратите внимание, что я расширил URL-адрес, включив токен с !, который должен передаваться буквально как суффикс more!):

$param = '{ ""job_start"": ""jdbc:mysql://127.0.0.1:3307/test&serverTimezone=UTC&more^!"" }'

Если вам нужно избежать существующей JSON строки программно :

# Unescaped JSON string, which in an ideal world you'd be able
# to pass as-is.
$param = '{ "job_start": "jdbc:mysql://127.0.0.1:3307/test&serverTimezone=UTC&more!" }'

# Escape the " chars.
$param = $param -replace '"', '""'

# If needed, also escape the ! chars.
$param = $param -replace '!', '^!'

В конечном итоге , обе проблемы должны быть исправлены в источнике - но это маловероятно, поскольку нарушит обратную совместимость .

Что касается PowerShell, этот выпуск GitHub содержит предысторию, технические детали, надежную функцию-оболочку, чтобы скрыть p проблемы и обсуждения того, как решить проблему, по крайней мере, на основе согласия.

0 голосов
/ 06 мая 2020

В этом вопросе Какие символы нужно экранировать при использовании Bash? , вы найдете все символы, которые вам следует избегать при передаче их в качестве обычных символов в оболочке, вы также заметите, что & является одним из них.

Теперь я понимаю, что если вы попробуете чтобы избежать этого, синтаксический анализатор JSON, который вы используете, вероятно, не сможет проанализировать строку. Таким образом, одним быстрым обходным решением было бы заменить & любым другим специальным неэкранированным символом, например @ или %, и выполнить шаг в своем приложении, где вы замените его на & перед синтаксическим анализом. Просто убедитесь, что символ, который вы будете использовать, не используется в ваших строках и не будет использоваться в любое время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...